blob: 5833e1b1a81658cda737f767ee328b4bb220b104 [file] [log] [blame]
Wenjie Qiao8a73a562023-02-23 18:37:14 +08001// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2/*
3 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
4 */
5
6#include <common.h>
7#include <command.h>
8#include <env.h>
9#include <malloc.h>
10#include <asm/byteorder.h>
11#ifdef CONFIG_AML_VPP
12#include <amlogic/media/vpp/vpp.h>
lizhi.hu506ddfa2024-07-10 21:35:41 +080013#else
14#define VPP_CM_RGB 0
15#define VPP_CM_YUV 2
16#define VPP_CM_INVALID 0xff
17__weak void vpp_matrix_update(int cfmt) {}
18__weak void vpp_viu2_matrix_update(int cfmt) {}
19__weak void vpp_viu3_matrix_update(int cfmt) {}
Wenjie Qiao8a73a562023-02-23 18:37:14 +080020#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +080021
Wenjie Qiao8a73a562023-02-23 18:37:14 +080022#include <amlogic/media/vout/aml_vout.h>
23#ifdef CONFIG_AML_HDMITX
24#ifdef CONFIG_AML_HDMITX20
25#include <amlogic/media/vout/hdmitx/hdmitx.h>
26#else
27#include <amlogic/media/vout/hdmitx21/hdmitx.h>
28#endif
29#endif
Wenjie Qiao8a73a562023-02-23 18:37:14 +080030#ifdef CONFIG_AML_CVBS
31#include <amlogic/media/vout/aml_cvbs.h>
32#endif
33#ifdef CONFIG_AML_LCD
34#include <amlogic/media/vout/lcd/aml_lcd.h>
35#endif
36
lizhi.hu506ddfa2024-07-10 21:35:41 +080037#ifdef CONFIG_AML_HDMITX
38static int vout_hdmi_hpd(struct hdmitx_dev *hdev, int hpd_st)
39{
Wenjie Qiao8a73a562023-02-23 18:37:14 +080040 char *hdmimode;
41 char *cvbsmode;
42 char *colorattribute;
lizhi.hu506ddfa2024-07-10 21:35:41 +080043 char *connector0_type;
44 int hdmi_enc_idx;
Wenjie Qiao8a73a562023-02-23 18:37:14 +080045
lizhi.hu506ddfa2024-07-10 21:35:41 +080046 /* get hdmi mode and colorattribute from env */
Wenjie Qiao8a73a562023-02-23 18:37:14 +080047 hdmimode = env_get("hdmimode");
48 if (hdmimode)
49 printf("%s: hdmimode=%s\n", __func__, hdmimode);
50
51 colorattribute = env_get("colorattribute");
52 if (colorattribute)
53 printf("%s: colorattribute=%s\n", __func__, colorattribute);
54
lizhi.hu506ddfa2024-07-10 21:35:41 +080055 connector0_type = env_get("connector0_type");
zhou.han57d1d212024-08-15 11:03:54 +080056 if (!connector0_type || !strcmp(connector0_type, "none")) {
57 env_set("connector0_type", "HDMI-A-A");
58 connector0_type = env_get("connector0_type");
59 printf("add default connector for HDMI-A-A\n");
60 } else {
61 printf("%s: connector0_type: %s\n", __func__, connector0_type);
62 }
lizhi.hu506ddfa2024-07-10 21:35:41 +080063
64 /* check whether the current connector is HDMI */
65 hdmi_enc_idx = is_valid_hdmi(connector0_type);
66
67 /*
68 * Check whether the current connector is HDMI or CVBS,
69 * and set a new value for the outputmode based on the HPD status.
70 * In this way, the LCD will not be processed.
71 * if hpd_st high, outputmode and connector0_type will be saved on hdmi side
72 * if hpd_st low, outputmode and connector0_type will be saved on cvbs side
73 */
74 if (hdmi_enc_idx || strcmp(connector0_type, "TV-1") == 0) {
75 if (!hpd_st) {
76 cvbsmode = env_get("cvbsmode");
77 if (cvbsmode)
78 env_set("outputmode", cvbsmode);
79 env_set("hdmichecksum", "0x00000000");
80 env_set("connector0_type", "TV-1");
81 } else {
82 if (!strstr(env_get("outputmode"), "hz"))
83 env_set("outputmode", "1080p60hz");
84 switch (hdev->enc_idx) {
85 case 0:
86 env_set("connector0_type", "HDMI-A-A");
87 break;
88 case 1:
89 env_set("connector0_type", "HDMI-A-B");
90 break;
91 case 2:
92 env_set("connector0_type", "HDMI-A-C");
93 break;
94 }
95 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +080096 }
97
98 return 1;
99}
100
lizhi.hu506ddfa2024-07-10 21:35:41 +0800101static int vout2_hdmi_hpd(struct hdmitx_dev *hdev, int hpd_st)
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800102{
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800103 char *hdmimode;
104 char *cvbsmode;
105 char *colorattribute;
lizhi.hu506ddfa2024-07-10 21:35:41 +0800106 char *connector1_type;
107 int hdmi_enc_idx;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800108
lizhi.hu506ddfa2024-07-10 21:35:41 +0800109 /* get hdmi mode and colorattribute from env */
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800110 hdmimode = env_get("hdmimode");
111 if (hdmimode)
112 printf("%s: hdmimode=%s\n", __func__, hdmimode);
113 colorattribute = env_get("colorattribute");
114 if (colorattribute)
115 printf("%s: colorattribute=%s\n", __func__, colorattribute);
lizhi.hu506ddfa2024-07-10 21:35:41 +0800116
117 connector1_type = env_get("connector1_type");
zhou.han57d1d212024-08-15 11:03:54 +0800118 if (!connector1_type || !strcmp(connector1_type, "none")) {
119 env_set("connector1_type", "HDMI-A-A");
120 connector1_type = env_get("connector1_type");
121 printf("add default connector for HDMI-A-A\n");
122 } else {
123 printf("%s: connector1_type: %s\n", __func__, connector1_type);
124 }
lizhi.hu506ddfa2024-07-10 21:35:41 +0800125
126 /* check whether the current connector is HDMI */
127 hdmi_enc_idx = is_valid_hdmi(connector1_type);
128
129 /*
130 * Check whether the current connector is HDMI or CVBS,
131 * and set a new value for the outputmode2 based on the HPD status.
132 * In this way, the LCD will not be processed.
133 * if hpd_st high, outputmode2 and connector1_type will be saved on hdmi side
134 * if hpd_st low, outputmode2 and connector1_type will be saved on cvbs side
135 */
136 if (hdmi_enc_idx || strcmp(connector1_type, "TV-1") == 0) {
137 if (!hpd_st) {
138 cvbsmode = env_get("cvbsmode");
139 if (cvbsmode)
140 env_set("outputmode2", cvbsmode);
141 env_set("hdmichecksum", "0x00000000");
142 } else {
143 if (!strstr(env_get("outputmode2"), "hz"))
144 env_set("outputmode2", "1080p60hz");
145 switch (hdev->enc_idx) {
146 case 0:
147 env_set("connector1_type", "HDMI-A-A");
148 break;
149 case 1:
150 env_set("connector1_type", "HDMI-A-B");
151 break;
152 case 2:
153 env_set("connector1_type", "HDMI-A-C");
154 break;
155 }
156 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800157 }
158
159 return 0;
160}
161
162int do_hpd_detect(cmd_tbl_t *cmdtp, int flag, int argc,
163 char *const argv[])
164{
165 char *st;
166 int hpd_st = 0;
167 unsigned long i = 0;
Wenjie Qiao4bdbbee2024-02-01 10:16:44 +0800168 /* some TV sets pull hpd high 1.3S after detect pwr5v high */
169 unsigned long hdmitx_hpd_wait_cnt = 15;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800170#ifdef CONFIG_AML_HDMITX20
171 struct hdmitx_dev *hdev = hdmitx_get_hdev();
172#else
173 struct hdmitx_dev *hdev = get_hdmitx21_device();
174#endif
175 int ret = 0;
176
177 st = env_get("hdmitx_hpd_bypass");
178 if (st && (strcmp((const char *)(uintptr_t)st[0], "1") == 0)) {
179 printf("hdmitx_hpd_bypass detect\n");
180 return 0;
181 }
182 st = env_get("hdmitx_hpd_wait_cnt");
183 if (st)
184 hdmitx_hpd_wait_cnt = simple_strtoul(st, NULL, 10);
185 hpd_st = hdev->hwop.get_hpd_state();
186
187 if (!hpd_st) {
188 /* For some TV, they cost extra time to pullup HPD after 5V */
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800189 for (i = 0; i < hdmitx_hpd_wait_cnt; i++) {
190 mdelay(100);
191 hpd_st = hdev->hwop.get_hpd_state();
192 if (hpd_st) {
193 printf("hpd delay %lu ms\n", (i + 1) * 100);
194 break;
195 }
196 }
197 }
198 printf("%s, hpd_state=%d\n", __func__, hpd_st);
199
lizhi.hu506ddfa2024-07-10 21:35:41 +0800200 ret = vout_hdmi_hpd(hdev, hpd_st);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800201 if (!ret)
lizhi.hu506ddfa2024-07-10 21:35:41 +0800202 vout2_hdmi_hpd(hdev, hpd_st);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800203
Wenjie Qiao4bdbbee2024-02-01 10:16:44 +0800204 hdev->hpd_state = hpd_st;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800205 return hpd_st;
206}
207#endif
208
lizhi.hua35829b2024-09-05 15:28:53 +0800209int aml_vout_prepare(uint8_t vout_idx, char *mode)
210{
211 unsigned short on_connector_dev = vout_connector_check(vout_idx);
212#if defined(CONFIG_AML_CVBS) || defined(CONFIG_AML_HDMITX) || defined(CONFIG_AML_LCD)
213 unsigned int mux_sel = VIU_MUX_MAX, venc_sel = VIU_MUX_MAX;
214 unsigned char viu_sel = vout_idx + 1; //VOUT_VIU1_SEL/VOUT_VIU2_SEL/VOUT_VIU3_SEL
215#endif
216#ifdef CONFIG_AML_LCD
217 unsigned int venc_index = on_connector_dev & 0xf;
218#endif
219#ifdef CONFIG_AML_HDMITX
220 struct vinfo_s *vinfo = vout_get_current_vinfo();
221 unsigned int fmt_mode = vinfo->vpp_post_out_color_fmt;
222#endif
223
224 switch (on_connector_dev & CONNECTOR_DEV_MASK) {
225 case CONNECTOR_DEV_LCD:
226#ifdef CONFIG_AML_LCD
227 mux_sel = aml_lcd_driver_outputmode_check(venc_index, mode);
228 venc_sel = mux_sel & 0xf;
229 if (venc_sel != VIU_MUX_ENCL)
230 break;
231 vout_viu_mux(viu_sel, VIU_MUX_ENCL | venc_index << 4);
232 vpp_matrix_update(VPP_CM_RGB);
233 aml_lcd_driver_prepare(venc_index, mode);
234 return CMD_RET_SUCCESS;
235#endif
236 break;
237 case CONNECTOR_DEV_HDMI:
238#ifdef CONFIG_AML_HDMITX
239 mux_sel = hdmi_outputmode_check(mode, 0);
240 venc_sel = mux_sel & 0xf;
241 if (venc_sel < VIU_MUX_MAX) {
242 vout_viu_mux(viu_sel, mux_sel);
243 if (fmt_mode == 1)
244 vpp_matrix_update(VPP_CM_RGB);
245 else
246 vpp_matrix_update(VPP_CM_YUV);
247 return CMD_RET_SUCCESS;
248 }
249#endif
250 break;
251 case CONNECTOR_DEV_CVBS:
252#ifdef CONFIG_AML_CVBS
253 mux_sel = cvbs_outputmode_check(mode);
254 venc_sel = mux_sel & 0xf;
255 if (venc_sel == VIU_MUX_ENCI) {
256 vout_viu_mux(viu_sel, mux_sel);
257 vpp_matrix_update(VPP_CM_YUV);
258 return CMD_RET_SUCCESS;
259 }
260#endif
261 break;
262 default:
263 break;
264 }
265 printf("VOUT: output prepare fail(0x%04x)\n", on_connector_dev);
266 vout_pr_connector_and_vmode();
267 return CMD_RET_FAILURE;
268}
269
270int aml_vout_output(uint8_t vout_idx, char *mode)
271{
272 unsigned short on_connector_dev = vout_connector_check(vout_idx);
273#ifdef CONFIG_AML_LCD
274 unsigned int venc_index = on_connector_dev & 0xf;
275#endif
276#if defined(CONFIG_AML_CVBS) || defined(CONFIG_AML_HDMITX) || defined(CONFIG_AML_LCD)
277 unsigned int mux_sel = VIU_MUX_MAX, venc_sel = VIU_MUX_MAX;
278#endif
279 int ret = -1;
280
281 if (!mode)
282 return -1;
283
284 switch (on_connector_dev & CONNECTOR_DEV_MASK) {
285 case CONNECTOR_DEV_LCD:
286#ifdef CONFIG_AML_LCD
287 mux_sel = aml_lcd_driver_outputmode_check(venc_index, mode);
288 venc_sel = mux_sel & 0xf;
289 if (venc_sel != VIU_MUX_ENCL)
290 break;
291 aml_lcd_driver_enable(venc_index, mode);
292 ret = 0;
293#endif
294 break;
295 case CONNECTOR_DEV_HDMI:
296#ifdef CONFIG_AML_HDMITX
297 mux_sel = hdmi_outputmode_check(mode, 0);
298 venc_sel = mux_sel & 0xf;
299 if (venc_sel >= VIU_MUX_MAX)
300 break;
301 // ret = aml_hdmitx_output(mode);
302#endif
303 break;
304 case CONNECTOR_DEV_CVBS:
305#ifdef CONFIG_AML_CVBS
306 mux_sel = cvbs_outputmode_check(mode);
307 venc_sel = mux_sel & 0xf;
308 if (venc_sel != VIU_MUX_ENCI)
309 break;
310 ret = cvbs_set_vmode(mode);
311#endif
312 break;
313 default:
314 break;
315 }
316
317 if (ret == 0) {
318 if (vout_idx == 0)
319 run_command("setenv vout_init enable", 0);
320 else if (vout_idx == 1)
321 run_command("setenv vout2_init enable", 0);
322 else if (vout_idx == 2)
323 run_command("setenv vout3_init enable", 0);
324 }
325
326 return ret;
327}
328
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800329static int do_vout_list(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
330{
lizhi.hu5252a222024-07-31 15:22:29 +0800331 vout_pr_connector_and_vmode();
lizhi.hu506ddfa2024-07-10 21:35:41 +0800332
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800333#ifdef CONFIG_AML_HDMITX
334#ifdef CONFIG_AML_HDMITX20
335 struct hdmitx_dev *hdmitx_device = hdmitx_get_hdev();
336#else
337 struct hdmitx_dev *hdmitx_device = get_hdmitx21_device();
338#endif
339#endif
340
341#ifdef CONFIG_AML_HDMITX
342 if (!hdmitx_device) {
343 printf("\nerror: hdmitx device is null\n");
344 } else {
345 printf("\nvalid hdmi mode:\n");
346 hdmitx_device->hwop.list_support_modes();
347 }
348#endif
349
350#ifdef CONFIG_AML_CVBS
351 printf("\nvalid cvbs mode:\n");
352 cvbs_show_valid_vmode();
353#endif
354
355#ifdef CONFIG_AML_LCD
356 printf("\nvalid lcd mode:\n");
357 aml_lcd_driver_list_support_mode();
358#endif
359
360 return CMD_RET_SUCCESS;
361}
362
lizhi.hu506ddfa2024-07-10 21:35:41 +0800363static int do_vout_prepare(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800364{
lizhi.hu506ddfa2024-07-10 21:35:41 +0800365 unsigned short on_connector_dev = vout_connector_check(0);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800366#if defined(CONFIG_AML_CVBS) || defined(CONFIG_AML_HDMITX) || defined(CONFIG_AML_LCD)
lizhi.hu506ddfa2024-07-10 21:35:41 +0800367 char mode[64]; //use stack instead of heap for smp
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800368 unsigned int mux_sel = VIU_MUX_MAX, venc_sel = VIU_MUX_MAX;
lizhi.hu506ddfa2024-07-10 21:35:41 +0800369
370 memset(mode, 0, 64);
371 sprintf(mode, "%s", argv[1]);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800372#endif
373#ifdef CONFIG_AML_LCD
lizhi.hu506ddfa2024-07-10 21:35:41 +0800374 unsigned int venc_index = on_connector_dev & 0xf;
375#endif
376#ifdef CONFIG_AML_HDMITX
377 struct vinfo_s *vinfo = vout_get_current_vinfo();
378 unsigned int fmt_mode = vinfo->vpp_post_out_color_fmt;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800379#endif
380
381 if (argc != 2)
382 return CMD_RET_FAILURE;
383
lizhi.hu506ddfa2024-07-10 21:35:41 +0800384 switch (on_connector_dev & CONNECTOR_DEV_MASK) {
385 case CONNECTOR_DEV_LCD:
386#ifdef CONFIG_AML_LCD
387 mux_sel = aml_lcd_driver_outputmode_check(venc_index, mode);
388 venc_sel = mux_sel & 0xf;
389 if (venc_sel != VIU_MUX_ENCL)
390 break;
391 vout_viu_mux(VOUT_VIU1_SEL, VIU_MUX_ENCL | venc_index << 4);
392 vpp_matrix_update(VPP_CM_RGB);
393 aml_lcd_driver_prepare(venc_index, mode);
394 return CMD_RET_SUCCESS;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800395#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800396 break;
397 case CONNECTOR_DEV_HDMI:
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800398#ifdef CONFIG_AML_HDMITX
lizhi.hu506ddfa2024-07-10 21:35:41 +0800399 mux_sel = hdmi_outputmode_check(mode, 0);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800400 venc_sel = mux_sel & 0xf;
401 if (venc_sel < VIU_MUX_MAX) {
402 vout_viu_mux(VOUT_VIU1_SEL, mux_sel);
lizhi.hu506ddfa2024-07-10 21:35:41 +0800403 if (fmt_mode == 1)
404 vpp_matrix_update(VPP_CM_RGB);
405 else
406 vpp_matrix_update(VPP_CM_YUV);
407 return CMD_RET_SUCCESS;
408 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800409#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800410 break;
411 case CONNECTOR_DEV_CVBS:
412#ifdef CONFIG_AML_CVBS
413 mux_sel = cvbs_outputmode_check(mode);
414 venc_sel = mux_sel & 0xf;
415 if (venc_sel == VIU_MUX_ENCI) {
416 vout_viu_mux(VOUT_VIU1_SEL, mux_sel);
417 vpp_matrix_update(VPP_CM_YUV);
418 return CMD_RET_SUCCESS;
419 }
420#endif
421 break;
422 default:
423 break;
424 }
425 printf("VOUT: output prepare fail(0x%04x)\n", on_connector_dev);
lizhi.hu5252a222024-07-31 15:22:29 +0800426 vout_pr_connector_and_vmode();
lizhi.hu506ddfa2024-07-10 21:35:41 +0800427 return CMD_RET_FAILURE;
428}
429
430static int do_vout_output(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
431{
432 unsigned short on_connector_dev = vout_connector_check(0);
433#if defined(CONFIG_AML_CVBS) || defined(CONFIG_AML_HDMITX) || defined(CONFIG_AML_LCD)
434 char mode[64]; //use stack instead of heap for smp
435 unsigned int mux_sel = VIU_MUX_MAX, venc_sel = VIU_MUX_MAX;
436
437 memset(mode, 0, 64);
438 sprintf(mode, "%s", argv[1]);
439#endif
440#ifdef CONFIG_AML_LCD
441 unsigned int venc_index = on_connector_dev & 0xf;
442#endif
443#ifdef CONFIG_AML_HDMITX
444 struct vinfo_s *vinfo = vout_get_current_vinfo();
445 unsigned int fmt_mode = vinfo->vpp_post_out_color_fmt;
446 char str[64];
447#endif
448
449 if (argc != 2)
450 return CMD_RET_FAILURE;
451
452 switch (on_connector_dev & CONNECTOR_DEV_MASK) {
453 case CONNECTOR_DEV_LCD:
454#ifdef CONFIG_AML_LCD
455 mux_sel = aml_lcd_driver_outputmode_check(venc_index, mode);
456 venc_sel = mux_sel & 0xf;
457 if (venc_sel != VIU_MUX_ENCL)
458 break;
459 vout_viu_mux(VOUT_VIU1_SEL, VIU_MUX_ENCL | venc_index << 4);
460 vpp_matrix_update(VPP_CM_RGB);
461 aml_lcd_driver_enable(venc_index, mode);
462 run_command("setenv vout_init enable", 0);
463 return CMD_RET_SUCCESS;
464#endif
465 break;
466 case CONNECTOR_DEV_HDMI:
467#ifdef CONFIG_AML_HDMITX
468 mux_sel = hdmi_outputmode_check(mode, 0);
469 venc_sel = mux_sel & 0xf;
470 if (venc_sel < VIU_MUX_MAX) {
471 vout_viu_mux(VOUT_VIU1_SEL, mux_sel);
472 if (fmt_mode == 1)
473 vpp_matrix_update(VPP_CM_RGB);
474 else
475 vpp_matrix_update(VPP_CM_YUV);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800476 memset(str, 0, sizeof(str));
477 sprintf(str, "hdmitx output %s", mode);
478 if (run_command(str, 0) == CMD_RET_SUCCESS)
479 run_command("setenv vout_init enable", 0);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800480 return CMD_RET_SUCCESS;
481 }
lizhi.hu506ddfa2024-07-10 21:35:41 +0800482#endif
483 break;
484 case CONNECTOR_DEV_CVBS:
485#ifdef CONFIG_AML_CVBS
486 mux_sel = cvbs_outputmode_check(mode);
487 venc_sel = mux_sel & 0xf;
488 if (venc_sel == VIU_MUX_ENCI) {
489 vout_viu_mux(VOUT_VIU1_SEL, mux_sel);
490 vpp_matrix_update(VPP_CM_YUV);
491 if (cvbs_set_vmode(mode) == 0) {
492 run_command("setenv vout_init enable", 0);
493 return CMD_RET_SUCCESS;
494 }
495 }
496#endif
497 break;
498 default:
499 break;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800500 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800501
lizhi.hu506ddfa2024-07-10 21:35:41 +0800502 printf("VOUT: output fail(0x%04x)\n", on_connector_dev);
lizhi.hu5252a222024-07-31 15:22:29 +0800503 vout_pr_connector_and_vmode();
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800504 return CMD_RET_FAILURE;
505}
506
507static int do_vout2_list(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
508{
lizhi.hu5252a222024-07-31 15:22:29 +0800509 vout_pr_connector_and_vmode();
lizhi.hu506ddfa2024-07-10 21:35:41 +0800510
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800511#ifdef CONFIG_AML_HDMITX
512#ifdef CONFIG_AML_HDMITX20
513 struct hdmitx_dev *hdmitx_device = hdmitx_get_hdev();
514#else
515 struct hdmitx_dev *hdmitx_device = get_hdmitx21_device();
516#endif
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800517
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800518 if (!hdmitx_device) {
519 printf("\nerror: hdmitx device is null\n");
520 } else {
521 printf("\nvalid hdmi mode:\n");
522 hdmitx_device->hwop.list_support_modes();
523 }
524#endif
525
526#ifdef CONFIG_AML_CVBS
527 printf("\nvalid cvbs mode:\n");
528 cvbs_show_valid_vmode();
529#endif
530
531#ifdef CONFIG_AML_LCD
532 printf("\nvalid lcd mode:\n");
533 aml_lcd_driver_list_support_mode();
534#endif
535
536 return CMD_RET_SUCCESS;
537}
538
539static int do_vout2_output(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
540{
lizhi.hu506ddfa2024-07-10 21:35:41 +0800541 unsigned short on_connector_dev = vout_connector_check(1);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800542#if defined(CONFIG_AML_CVBS) || defined(CONFIG_AML_HDMITX) || defined(CONFIG_AML_LCD)
lizhi.hu506ddfa2024-07-10 21:35:41 +0800543 char mode[64]; //use stack instead of heap for smp
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800544 unsigned int mux_sel = VIU_MUX_MAX, venc_sel = VIU_MUX_MAX;
lizhi.hu506ddfa2024-07-10 21:35:41 +0800545
546 memset(mode, 0, 64);
547 sprintf(mode, "%s", argv[1]);
548#endif
549#ifdef CONFIG_AML_LCD
550 unsigned int venc_index = on_connector_dev & 0xf;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800551#endif
552#ifdef CONFIG_AML_HDMITX
553 char str[64];
554#endif
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800555
556 if (argc != 2)
557 return CMD_RET_FAILURE;
558
lizhi.hu506ddfa2024-07-10 21:35:41 +0800559 switch (on_connector_dev & CONNECTOR_DEV_MASK) {
560 case CONNECTOR_DEV_LCD:
561#ifdef CONFIG_AML_LCD
562 mux_sel = aml_lcd_driver_outputmode_check(venc_index, mode);
563 venc_sel = mux_sel & 0xf;
564 if (venc_sel != VIU_MUX_ENCL)
565 break;
566 aml_lcd_driver_enable(venc_index, mode);
567 run_command("setenv vout2_init enable", 0);
568 return CMD_RET_SUCCESS;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800569#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800570 break;
571 case CONNECTOR_DEV_HDMI:
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800572#ifdef CONFIG_AML_HDMITX
lizhi.hu506ddfa2024-07-10 21:35:41 +0800573 mux_sel = hdmi_outputmode_check(mode, 0);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800574 venc_sel = mux_sel & 0xf;
575 if (venc_sel < VIU_MUX_MAX) {
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800576 memset(str, 0, sizeof(str));
577 sprintf(str, "hdmitx output %s", mode);
578 run_command(str, 0);
lizhi.hu506ddfa2024-07-10 21:35:41 +0800579 run_command("setenv vout2_init enable", 0);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800580 return CMD_RET_SUCCESS;
581 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800582#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800583 break;
584 case CONNECTOR_DEV_CVBS:
585#ifdef CONFIG_AML_CVBS
586 mux_sel = cvbs_outputmode_check(mode);
587 venc_sel = mux_sel & 0xf;
588 if (venc_sel == VIU_MUX_ENCI) {
589 if (cvbs_set_vmode(mode) == 0) {
590 run_command("setenv vout2_init enable", 0);
591 return CMD_RET_SUCCESS;
592 }
593 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800594#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800595 break;
596 default:
597 break;
598 }
599 printf("VOUT2: output fail(0x%04x)\n", on_connector_dev);
lizhi.hu5252a222024-07-31 15:22:29 +0800600 vout_pr_connector_and_vmode();
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800601 return CMD_RET_FAILURE;
lizhi.hu506ddfa2024-07-10 21:35:41 +0800602
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800603}
604
605static int do_vout2_prepare(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
606{
lizhi.hu506ddfa2024-07-10 21:35:41 +0800607 unsigned short on_connector_dev = vout_connector_check(1);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800608#if defined(CONFIG_AML_CVBS) || defined(CONFIG_AML_HDMITX) || defined(CONFIG_AML_LCD)
lizhi.hu506ddfa2024-07-10 21:35:41 +0800609 char mode[64]; //use stack instead of heap for smp
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800610 unsigned int mux_sel = VIU_MUX_MAX, venc_sel = VIU_MUX_MAX;
lizhi.hu506ddfa2024-07-10 21:35:41 +0800611
612 memset(mode, 0, 64);
613 sprintf(mode, "%s", argv[1]);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800614#endif
615#ifdef CONFIG_AML_LCD
lizhi.hu506ddfa2024-07-10 21:35:41 +0800616 unsigned int venc_index = on_connector_dev & 0xf;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800617#endif
618
619 if (argc != 2)
620 return CMD_RET_FAILURE;
621
lizhi.hu506ddfa2024-07-10 21:35:41 +0800622 switch (on_connector_dev & CONNECTOR_DEV_MASK) {
623 case CONNECTOR_DEV_LCD:
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800624#ifdef CONFIG_AML_LCD
lizhi.hu506ddfa2024-07-10 21:35:41 +0800625 mux_sel = aml_lcd_driver_outputmode_check(venc_index, mode);
626 venc_sel = mux_sel & 0xf;
627 if (venc_sel != VIU_MUX_ENCL)
628 break;
629 vout_viu_mux(VOUT_VIU2_SEL, VIU_MUX_ENCL | venc_index << 4);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800630 vpp_viu2_matrix_update(VPP_CM_RGB);
lizhi.hu506ddfa2024-07-10 21:35:41 +0800631 aml_lcd_driver_prepare(venc_index, mode);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800632 return CMD_RET_SUCCESS;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800633#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800634 break;
635 case CONNECTOR_DEV_HDMI:
636#ifdef CONFIG_AML_HDMITX
637 mux_sel = hdmi_outputmode_check(mode, 0);
638 venc_sel = mux_sel & 0xf;
639 if (venc_sel < VIU_MUX_MAX) {
640 vout_viu_mux(VOUT_VIU2_SEL, mux_sel);
641 vpp_viu2_matrix_update(VPP_CM_YUV);
642 return CMD_RET_SUCCESS;
643 }
644#endif
645 break;
646 case CONNECTOR_DEV_CVBS:
647#ifdef CONFIG_AML_CVBS
648 mux_sel = cvbs_outputmode_check(mode);
649 venc_sel = mux_sel & 0xf;
650 if (venc_sel == VIU_MUX_ENCI) {
651 vout_viu_mux(VOUT_VIU2_SEL, mux_sel);
652 vpp_viu2_matrix_update(VPP_CM_YUV);
653 return CMD_RET_SUCCESS;
654 }
655#endif
656 break;
657 default:
658 break;
659 }
660 printf("VOUT2: output prepare fail(0x%04x)\n", on_connector_dev);
lizhi.hu5252a222024-07-31 15:22:29 +0800661 vout_pr_connector_and_vmode();
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800662 return CMD_RET_FAILURE;
663}
664
665static int do_vout3_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
666{
lizhi.hu5252a222024-07-31 15:22:29 +0800667 vout_pr_connector_and_vmode();
lizhi.hu506ddfa2024-07-10 21:35:41 +0800668
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800669#ifdef CONFIG_AML_HDMITX
670#ifdef CONFIG_AML_HDMITX20
671 struct hdmitx_dev *hdmitx_device = hdmitx_get_hdev();
672#else
673 struct hdmitx_dev *hdmitx_device = get_hdmitx21_device();
674#endif
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800675
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800676 if (!hdmitx_device) {
677 printf("\nerror: hdmitx device is null\n");
678 } else {
679 printf("\nvalid hdmi mode:\n");
680 hdmitx_device->hwop.list_support_modes();
681 }
682#endif
683
684#ifdef CONFIG_AML_CVBS
685 printf("\nvalid cvbs mode:\n");
686 cvbs_show_valid_vmode();
687#endif
688
689#ifdef CONFIG_AML_LCD
690 printf("\nvalid lcd mode:\n");
691 aml_lcd_driver_list_support_mode();
692#endif
693
694 return CMD_RET_SUCCESS;
695}
696
697static int do_vout3_output(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
698{
lizhi.hu506ddfa2024-07-10 21:35:41 +0800699 unsigned short on_connector_dev = vout_connector_check(2);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800700#if defined(CONFIG_AML_CVBS) || defined(CONFIG_AML_HDMITX) || defined(CONFIG_AML_LCD)
lizhi.hu506ddfa2024-07-10 21:35:41 +0800701 char mode[64]; //use stack instead of heap for smp
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800702 unsigned int mux_sel = VIU_MUX_MAX, venc_sel = VIU_MUX_MAX;
lizhi.hu506ddfa2024-07-10 21:35:41 +0800703
704 memset(mode, 0, 64);
705 sprintf(mode, "%s", argv[1]);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800706#endif
707#ifdef CONFIG_AML_HDMITX
708 char str[64];
709#endif
710#ifdef CONFIG_AML_LCD
lizhi.hu506ddfa2024-07-10 21:35:41 +0800711 unsigned int venc_index = on_connector_dev & 0xf;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800712#endif
713
714 if (argc != 2)
715 return CMD_RET_FAILURE;
716
lizhi.hu506ddfa2024-07-10 21:35:41 +0800717 switch (on_connector_dev & CONNECTOR_DEV_MASK) {
718 case CONNECTOR_DEV_LCD:
719#ifdef CONFIG_AML_LCD
720 mux_sel = aml_lcd_driver_outputmode_check(venc_index, mode);
721 venc_sel = mux_sel & 0xf;
722 if (venc_sel != VIU_MUX_ENCL)
723 break;
724 aml_lcd_driver_enable(venc_index, mode);
725 run_command("setenv vout3_init enable", 0);
726 return CMD_RET_SUCCESS;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800727#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800728 break;
729 case CONNECTOR_DEV_HDMI:
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800730#ifdef CONFIG_AML_HDMITX
lizhi.hu506ddfa2024-07-10 21:35:41 +0800731 mux_sel = hdmi_outputmode_check(mode, 0);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800732 venc_sel = mux_sel & 0xf;
733 if (venc_sel < VIU_MUX_MAX) {
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800734 memset(str, 0, sizeof(str));
735 sprintf(str, "hdmitx output %s", mode);
736 run_command(str, 0);
lizhi.hu506ddfa2024-07-10 21:35:41 +0800737 run_command("setenv vout3_init enable", 0);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800738 return CMD_RET_SUCCESS;
739 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800740#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800741 break;
742 case CONNECTOR_DEV_CVBS:
743#ifdef CONFIG_AML_CVBS
744 mux_sel = cvbs_outputmode_check(mode);
745 venc_sel = mux_sel & 0xf;
746 if (venc_sel == VIU_MUX_ENCI) {
747 if (cvbs_set_vmode(mode) == 0) {
748 run_command("setenv vout3_init enable", 0);
749 return CMD_RET_SUCCESS;
750 }
751 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800752#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800753 break;
754 default:
755 break;
756 }
757 printf("VOUT3: output fail(0x%04x)\n", on_connector_dev);
lizhi.hu5252a222024-07-31 15:22:29 +0800758 vout_pr_connector_and_vmode();
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800759 return CMD_RET_FAILURE;
760}
761
762static int do_vout3_prepare(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
763{
lizhi.hu506ddfa2024-07-10 21:35:41 +0800764 unsigned short on_connector_dev = vout_connector_check(2);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800765#if defined(CONFIG_AML_CVBS) || defined(CONFIG_AML_HDMITX) || defined(CONFIG_AML_LCD)
lizhi.hu506ddfa2024-07-10 21:35:41 +0800766 char mode[64]; //use stack instead of heap for smp
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800767 unsigned int mux_sel = VIU_MUX_MAX, venc_sel = VIU_MUX_MAX;
lizhi.hu506ddfa2024-07-10 21:35:41 +0800768
769 memset(mode, 0, (sizeof(char) * 64));
770 sprintf(mode, "%s", argv[1]);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800771#endif
772#ifdef CONFIG_AML_LCD
lizhi.hu506ddfa2024-07-10 21:35:41 +0800773 unsigned int venc_index = on_connector_dev & 0xf;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800774#endif
775
776 if (argc != 2)
777 return CMD_RET_FAILURE;
778
lizhi.hu506ddfa2024-07-10 21:35:41 +0800779 switch (on_connector_dev & CONNECTOR_DEV_MASK) {
780 case CONNECTOR_DEV_LCD:
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800781#ifdef CONFIG_AML_LCD
lizhi.hu506ddfa2024-07-10 21:35:41 +0800782 mux_sel = aml_lcd_driver_outputmode_check(venc_index, mode);
783 venc_sel = mux_sel & 0xf;
784 if (venc_sel != VIU_MUX_ENCL)
785 break;
786 vout_viu_mux(VOUT_VIU3_SEL, VIU_MUX_ENCL | venc_index << 4);
787 vpp_viu3_matrix_update(VPP_CM_RGB);
788 aml_lcd_driver_prepare(venc_index, mode);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800789 return CMD_RET_SUCCESS;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800790#endif
lizhi.hu506ddfa2024-07-10 21:35:41 +0800791 break;
792 case CONNECTOR_DEV_HDMI:
793#ifdef CONFIG_AML_HDMITX
794 mux_sel = hdmi_outputmode_check(mode, 0);
795 venc_sel = mux_sel & 0xf;
796 if (venc_sel < VIU_MUX_MAX) {
797 vout_viu_mux(VOUT_VIU3_SEL, mux_sel);
798 vpp_viu3_matrix_update(VPP_CM_YUV);
799 return CMD_RET_SUCCESS;
800 }
801#endif
802 break;
803 case CONNECTOR_DEV_CVBS:
804#ifdef CONFIG_AML_CVBS
805 mux_sel = cvbs_outputmode_check(mode);
806 venc_sel = mux_sel & 0xf;
807 if (venc_sel == VIU_MUX_ENCI) {
808 vout_viu_mux(VOUT_VIU3_SEL, mux_sel);
809 vpp_viu3_matrix_update(VPP_CM_YUV);
810 return CMD_RET_SUCCESS;
811 }
812#endif
813 break;
814 default:
815 break;
816 }
817 printf("VOUT3: output prepare fail(0x%04x)\n", on_connector_dev);
lizhi.hu5252a222024-07-31 15:22:29 +0800818 vout_pr_connector_and_vmode();
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800819 return CMD_RET_FAILURE;
820}
821
822static int do_vout_info(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
823{
824 vout_vinfo_dump();
825
826 return CMD_RET_SUCCESS;
827}
828
lizhi.hu506ddfa2024-07-10 21:35:41 +0800829#define VOUT_HELPER_STRING \
830 "vout/vout2/vout3 [list | output format | info]\n" \
831 " list : list for valid video mode names\n" \
832 " prepare : prepare\n" \
833 " format : perfered output video mode\n" \
834 " info : dump vinfo\n"
835
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800836static cmd_tbl_t cmd_vout_sub[] = {
lizhi.hu506ddfa2024-07-10 21:35:41 +0800837 U_BOOT_CMD_MKENT(list, 1, 1, do_vout_list, "", ""),
838 U_BOOT_CMD_MKENT(prepare, 3, 1, do_vout_prepare, "", ""),
839 U_BOOT_CMD_MKENT(output, 3, 1, do_vout_output, "", ""),
840 U_BOOT_CMD_MKENT(info, 1, 1, do_vout_info, "", ""),
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800841};
842
843static int do_vout(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
844{
845 cmd_tbl_t *c;
846
847 if (argc < 2)
848 return cmd_usage(cmdtp);
849
850 argc--;
851 argv++;
852
853 c = find_cmd_tbl(argv[0], &cmd_vout_sub[0], ARRAY_SIZE(cmd_vout_sub));
854
855 if (c)
856 return c->cmd(cmdtp, flag, argc, argv);
857 else
858 return cmd_usage(cmdtp);
859}
860
lizhi.hu506ddfa2024-07-10 21:35:41 +0800861U_BOOT_CMD(vout, CONFIG_SYS_MAXARGS, 1, do_vout, "VOUT sub-system", VOUT_HELPER_STRING);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800862
863static cmd_tbl_t cmd_vout2_sub[] = {
lizhi.hu506ddfa2024-07-10 21:35:41 +0800864 U_BOOT_CMD_MKENT(list, 1, 1, do_vout2_list, "", ""),
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800865 U_BOOT_CMD_MKENT(prepare, 3, 1, do_vout2_prepare, "", ""),
lizhi.hu506ddfa2024-07-10 21:35:41 +0800866 U_BOOT_CMD_MKENT(output, 3, 1, do_vout2_output, "", ""),
867 U_BOOT_CMD_MKENT(info, 1, 1, do_vout_info, "", ""),
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800868};
869
870static int do_vout2(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
871{
872 cmd_tbl_t *c;
873
874 if (argc < 2)
875 return cmd_usage(cmdtp);
876
877 argc--;
878 argv++;
879
880 c = find_cmd_tbl(argv[0], &cmd_vout2_sub[0], ARRAY_SIZE(cmd_vout2_sub));
881
882 if (c)
883 return c->cmd(cmdtp, flag, argc, argv);
884 else
885 return cmd_usage(cmdtp);
886}
887
lizhi.hu506ddfa2024-07-10 21:35:41 +0800888U_BOOT_CMD(vout2, CONFIG_SYS_MAXARGS, 1, do_vout2, "VOUT2 sub-system", VOUT_HELPER_STRING);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800889
890static cmd_tbl_t cmd_vout3_sub[] = {
lizhi.hu506ddfa2024-07-10 21:35:41 +0800891 U_BOOT_CMD_MKENT(list, 1, 1, do_vout3_list, "", ""),
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800892 U_BOOT_CMD_MKENT(prepare, 3, 1, do_vout3_prepare, "", ""),
lizhi.hu506ddfa2024-07-10 21:35:41 +0800893 U_BOOT_CMD_MKENT(output, 3, 1, do_vout3_output, "", ""),
894 U_BOOT_CMD_MKENT(info, 1, 1, do_vout_info, "", ""),
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800895};
896
897static int do_vout3(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
898{
899 cmd_tbl_t *c;
900
901 if (argc < 2)
902 return cmd_usage(cmdtp);
903
904 argc--;
905 argv++;
906
907 c = find_cmd_tbl(argv[0], &cmd_vout3_sub[0], ARRAY_SIZE(cmd_vout3_sub));
908
909 if (c)
910 return c->cmd(cmdtp, flag, argc, argv);
911 else
912 return cmd_usage(cmdtp);
913}
914
lizhi.hu506ddfa2024-07-10 21:35:41 +0800915U_BOOT_CMD(vout3, CONFIG_SYS_MAXARGS, 1, do_vout3, "VOUT3 sub-system", VOUT_HELPER_STRING);