blob: 2ab73b86040da8295c5292c08fcc46c8b131f5b6 [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#include <amlogic/clk_measure.h>
12#include <amlogic/media/vout/hdmitx21/hdmitx.h>
Wenjie Qiao389d3ea2023-05-25 16:07:03 +080013#include <linux/delay.h>
Wenjie Qiao8a73a562023-02-23 18:37:14 +080014#include <amlogic/media/dv/dolby_vision.h>
15#include <linux/libfdt_env.h>
16
17static unsigned char edid_raw_buf[512] = {0};
Wenjie Qiao389d3ea2023-05-25 16:07:03 +080018/* there may be outputmode/2/3 when in multi-display case,
19 * sel_hdmimode is used to save the selected hdmi mode
20 */
21static char sel_hdmimode[MODE_LEN] = {0};
Wenjie Qiao8a73a562023-02-23 18:37:14 +080022
23static void dump_full_edid(const unsigned char *buf)
24{
25 int i;
26 int blk_no;
27
28 if (!buf)
29 return;
30 blk_no = buf[126] + 1;
31 if (blk_no > 4)
32 blk_no = 4;
Wenjie Qiao389d3ea2023-05-25 16:07:03 +080033
34 if (blk_no == 2)
35 if (buf[128 + 4] == 0xe2 && buf[128 + 5] == 0x78)
36 blk_no = buf[128 + 6] + 1;
37 if (blk_no > EDID_BLK_NO)
38 blk_no = EDID_BLK_NO;
39
Wenjie Qiao8a73a562023-02-23 18:37:14 +080040 printf("dump EDID rawdata\n");
41 printf(" ");
42 for (i = 0; i < blk_no * EDID_BLK_SIZE; i++)
43 printf("%02x", buf[i]);
44 printf("\n");
45}
46
47static int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
48{
49 unsigned char st = 0;
50 struct hdmitx_dev *hdev = get_hdmitx21_device();
51
52 memset(edid_raw_buf, 0, ARRAY_SIZE(edid_raw_buf));
53
54 st = hdev->hwop.read_edid(edid_raw_buf);
55
56 if (!st)
57 printf("edid read failed\n");
58
59 return st;
60}
61
62static int do_rx_det(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
63{
64 unsigned char st = 0;
65 struct hdmitx_dev *hdev = get_hdmitx21_device();
66
67 memset(edid_raw_buf, 0, ARRAY_SIZE(edid_raw_buf));
68
69 // read edid raw data
70 // current only support read 1 byte edid data
71 st = hdev->hwop.read_edid(edid_raw_buf);
72
73 if (st) {
74 if (edid_raw_buf[250] == 0xfb && edid_raw_buf[251] == 0x0c) {
75 printf("RX is FBC\n");
76
77 // set outputmode ENV
78 switch (edid_raw_buf[252] & 0x0f) {
79 case 0x0:
80 run_command("setenv outputmode 1080p50hz", 0);
81 break;
82 case 0x1:
83 run_command("setenv outputmode 2160p50hz420", 0);
84 break;
85 case 0x2:
86 run_command("setenv outputmode 1080p50hz44410bit", 0);
87 break;
88 case 0x3:
89 run_command("setenv outputmode 2160p50hz42010bit", 0);
90 break;
91 case 0x4:
92 run_command("setenv outputmode 2160p50hz42210bit", 0);
93 break;
94 case 0x5:
95 run_command("setenv outputmode 2160p50hz", 0);
96 break;
97 default:
98 run_command("setenv outputmode 1080p50hz", 0);
99 break;
100 }
101
102 /*et RX 3D Info*/
103 switch ((edid_raw_buf[252] >> 4) & 0x0f) {
104 case 0x00:
105 run_command("setenv rx_3d_info 0", 0);
106 break;
107 case 0x01:
108 run_command("setenv rx_3d_info 1", 0);
109 break;
110 case 0x02:
111 run_command("setenv rx_3d_info 2", 0);
112 break;
113 case 0x03:
114 run_command("setenv rx_3d_info 3", 0);
115 break;
116 case 0x04:
117 run_command("setenv rx_3d_info 4", 0);
118 break;
119 default:
120 break;
121 }
122
123 switch (edid_raw_buf[253]) {
124 case 0x1:
125 /*TODO*/
126 break;
127 case 0x2:
128 /*TODO*/
129 break;
130 default:
131 break;
132 }
133 }
134 } else {
135 printf("edid read failed\n");
136 }
137
138 return st;
139}
140
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800141static void save_default_720p(void)
142{
143 memcpy(sel_hdmimode, DEFAULT_HDMI_MODE, sizeof(DEFAULT_HDMI_MODE));
144 if (is_hdmi_mode(env_get("outputmode")))
145 env_set("outputmode", DEFAULT_HDMI_MODE);
146 else if (is_hdmi_mode(env_get("outputmode2")))
147 env_set("outputmode2", DEFAULT_HDMI_MODE);
148 else if (is_hdmi_mode(env_get("outputmode3")))
149 env_set("outputmode3", DEFAULT_HDMI_MODE);
150 env_set("colorattribute", DEFAULT_COLOR_FORMAT);
151}
152
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800153static void hdmitx_mask_rx_info(struct hdmitx_dev *hdev)
154{
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800155 if (!hdev || !hdev->para)
156 return;
157
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800158 if (env_get("colorattribute"))
159 hdmitx21_get_fmtpara(sel_hdmimode, env_get("colorattribute"));
160
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800161 /* when current output color depth is 8bit, mask hdr capability */
162 /* refer to SWPL-44445 for more detail */
163 if (hdev->para->cd == COLORDEPTH_24B)
164 memset(&hdev->RXCap.hdr_info, 0, sizeof(struct hdr_info));
165}
166
167static int do_output(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
168{
169 const struct hdmi_timing *timing = NULL;
170 struct hdmitx_dev *hdev = get_hdmitx21_device();
171
Wenjie Qiao39b85512023-08-03 19:32:08 +0800172 //hdmitx21_pxp_init(1);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800173 if (argc < 1)
174 return cmd_usage(cmdtp);
175
176 if (strcmp(argv[1], "list") == 0) {
177 hdev->hwop.list_support_modes();
178 } else if (strcmp(argv[1], "bist") == 0) {
179 unsigned int mode = 0;
180
181 if (strcmp(argv[2], "off") == 0)
182 mode = 0;
183 else if (strcmp(argv[2], "line") == 0)
184 mode = 2;
185 else if (strcmp(argv[2], "dot") == 0)
186 mode = 3;
187 else if (strcmp(argv[2], "x") == 0)
188 mode = 'x';
189 else if (strcmp(argv[2], "X") == 0)
190 mode = 'X';
191 else
192 mode = simple_strtoul(argv[2], NULL, 10);
193 hdev->hwop.test_bist(mode);
194 } else if (strcmp(argv[1], "prbs") == 0) {
195 hdev->para->cs = HDMI_COLORSPACE_RGB;
196 hdev->para->cd = COLORDEPTH_24B;
197 hdev->vic = HDMI_16_1920x1080p60_16x9;
198 hdmitx21_set(hdev);
199 hdev->hwop.test_prbs();
200 } else if (strncmp(argv[1], "div40", 5) == 0) {
201 bool div40 = 0;
202
203 if (argv[1][5] == '1')
204 div40 = 1;
205 hdev->hwop.set_div40(div40);
206 } else { /* "output" */
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800207 if (!hdev->pxp_mode) {
208 if (!edid_parsing_ok(hdev)) {
209 /* in SWPL-34712: if EDID parsing error in kernel,
210 * only forcely output default mode(480p,RGB,8bit)
211 * in sysctl, not save the default mode to env.
212 * if uboot follow this rule, will cause issue OTT-19333:
213 * uboot read edid error and then output default mode,
214 * without save it mode env. if then kernel edid normal,
215 * sysctrl/kernel get mode from env, the actual output
216 * mode differs with outputmode env,it will
217 * cause display abnormal(such as stretch). so don't
218 * follow this rule in uboot, that's to say the actual
219 * output mode needs to stays with the outputmode env.
220 */
221 printf("edid parsing ng, forcely output 720p, rgb,8bit\n");
222 save_default_720p();
223 hdev->vic = HDMI_4_1280x720p60_16x9;
224 hdev->para =
225 hdmitx21_get_fmtpara("720p60hz", "rgb,8bit");
226 hdev->para->cs = HDMI_COLORSPACE_RGB;
227 hdev->para->cd = COLORDEPTH_24B;
228 hdmitx21_set(hdev);
229 return CMD_RET_SUCCESS;
230 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800231 }
232 if (!env_get("colorattribute"))
233 env_set("colorattribute", "444,8bit");
234 hdev->para = hdmitx21_get_fmtpara(argv[1], env_get("colorattribute"));
235 hdev->vic = hdev->para->timing.vic;
236 if (hdev->vic == HDMI_UNKNOWN) {
237 /* Not find VIC */
238 printf("Not find '%s' mapped VIC\n", argv[1]);
239 return CMD_RET_FAILURE;
240 }
241 if (strstr(argv[1], "hz420"))
242 hdev->para->cs = HDMI_COLORSPACE_YUV420;
243 /* S5 support over 6G, T7 not support */
244 switch (hdev->vic) {
245 case HDMI_96_3840x2160p50_16x9:
246 case HDMI_97_3840x2160p60_16x9:
247 case HDMI_101_4096x2160p50_256x135:
248 case HDMI_102_4096x2160p60_256x135:
249 case HDMI_106_3840x2160p50_64x27:
250 case HDMI_107_3840x2160p60_64x27:
251 if (hdev->chip_type == MESON_CPU_ID_T7) {
252 if (hdev->para->cs == HDMI_COLORSPACE_RGB ||
253 hdev->para->cs == HDMI_COLORSPACE_YUV444) {
254 if (hdev->para->cd != COLORDEPTH_24B) {
255 printf("vic %d cs %d has no cd %d\n",
256 hdev->vic,
257 hdev->para->cs,
258 hdev->para->cd);
259 hdev->para->cd = COLORDEPTH_24B;
260 printf("set cd as %d\n", COLORDEPTH_24B);
261 }
262 }
263 }
264 break;
265 default:
266 /* In Spec2.1 Table 7-34, greater than 2160p30hz will support y420 */
267 timing = hdmitx21_gettiming_from_vic(hdev->vic);
268 if (!timing)
269 break;
270 if (timing->v_active > 2160 && timing->v_freq > 30000)
271 break;
272 if (timing->v_active >= 4320)
273 break;
274 if (hdev->para->cs == HDMI_COLORSPACE_YUV420) {
275 printf("vic %d has no cs %d\n", hdev->vic,
276 hdev->para->cs);
277 hdev->para->cs = HDMI_COLORSPACE_YUV444;
278 printf("set cs as %d\n", HDMI_COLORSPACE_YUV444);
279 }
280 break;
281 }
282 printf("set hdmitx VIC = %d CS = %d CD = %d\n",
283 hdev->vic, hdev->para->cs, hdev->para->cd);
284 /* currently, hdmi mode is always set, if
285 * mode set abort/exit, need to add return
286 * result of mode setting, so that vout
287 * driver will pass it to kernel, and do
288 * mode setting again when vout init in kernel
289 */
290 hdmitx21_set(hdev);
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800291 if (hdev->frl_rate && !hdev->flt_train_st) {
292 /* FLT training failed, need go to tmds mode */
293 printf("hdmitx frl training failed, set tmds mode\n");
294 run_command("setenv hdmimode 1080p60hz", 0);
295 run_command("setenv colorattribute 422,12bit", 0);
296 run_command("run init_display_base", 0);
297 }
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800298 }
299 return CMD_RET_SUCCESS;
300}
301
302static int do_clkmsr(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
303{
304 clk_msr(51);
305 clk_msr(59);
306 clk_msr(61);
307 clk_msr(76);
308 clk_msr(77);
309 clk_msr(78);
310 clk_msr(80);
311 clk_msr(81);
312 clk_msr(82);
313 clk_msr(83);
314 clk_msr(219);
315 clk_msr(220);
316 clk_msr(221);
317 clk_msr(222);
318 return CMD_RET_SUCCESS;
319}
320
321static int do_blank(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
322{
323 struct hdmitx_dev *hdev = get_hdmitx21_device();
324
325 if (argc < 1)
326 return cmd_usage(cmdtp);
327
328 if (strcmp(argv[1], "1") == 0)
329 hdev->hwop.output_blank(1);
330 if (strcmp(argv[1], "0") == 0)
331 hdev->hwop.output_blank(0);
332
333 return CMD_RET_SUCCESS;
334}
335
336static int do_off(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
337{
338 struct hdmitx_dev *hdev = get_hdmitx21_device();
339
340 hdev->vic = HDMI_UNKNOWN;
341 hdev->hwop.turn_off();
342 printf("turn off hdmitx\n");
343 return 1;
344}
345
346static int do_dump(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
347{
348 struct hdmitx_dev *hdev = get_hdmitx21_device();
349
350 hdev->hwop.dump_regs();
351 return 1;
352}
353
354static int do_reg(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
355{
356 unsigned long addr = 0;
357 unsigned int data = 0;
358
359 if (argc < 1)
360 return cmd_usage(cmdtp);
361
362 if (strncmp(argv[1], "rh", 2) == 0) {
363 addr = strtoul(argv[1] + 2, NULL, 16);
364 data = hdmitx21_rd_reg((unsigned int)addr);
365 printf("rd[0x%lx] 0x%x\n", addr, data);
366 }
367
368 if (strncmp(argv[1], "wh", 2) == 0) {
369 addr = strtoul(argv[1] + 2, NULL, 16);
370 data = strtoul(argv[2], NULL, 16);
371 hdmitx21_wr_reg(addr, data);
372 printf("wr[0x%lx] 0x%x\n", addr, data);
373 }
374
375 return 1;
376}
377
378static bool check_vic_exist(struct hdmitx_dev *hdev, enum hdmi_vic vic,
379 int count)
380{
381 struct rx_cap *rxcap = NULL;
382 int i;
383
384 rxcap = &hdev->RXCap;
385 for (i = 0; i < count; i++)
386 if (vic == rxcap->VIC[i])
387 return 1;
388
389 return 0;
390}
391
392static void disp_cap_show(struct hdmitx_dev *hdev)
393{
394 struct rx_cap *rxcap = NULL;
395 const struct hdmi_timing *timing = NULL;
396 enum hdmi_vic vic;
397 int i;
398
399 if (!hdev)
400 return;
401
402 rxcap = &hdev->RXCap;
403 printf("disp_cap\n");
404 for (i = 0; i < rxcap->VIC_count && i < VIC_MAX_NUM; i++) {
405 vic = rxcap->VIC[i];
406 if (check_vic_exist(hdev, vic, i))
407 continue;
408 timing = hdmitx21_gettiming_from_vic(vic);
409 if (timing && vic < HDMITX_VESA_OFFSET && !is_vic_over_limited_1080p(vic))
410 printf(" %s\n", timing->sname ? timing->sname : timing->name);
411 }
412}
413
414static void vesa_cap_show(struct hdmitx_dev *hdev)
415{
416}
417
418static void dc_cap_show(struct hdmitx_dev *hdev)
419{
420 enum hdmi_vic vic = HDMI_0_UNKNOWN;
421 struct rx_cap *prxcap = &hdev->RXCap;
422 const struct dv_info *dv = &hdev->RXCap.dv_info;
423
424 printf("dc_cap\n");
425 if (prxcap->dc_36bit_420)
426 printf("420,12bit\n");
427 if (prxcap->dc_30bit_420) {
428 printf("420,10bit\n");
429 printf("420,8bit\n");
430 } else {
431 vic = hdmitx_edid_get_VIC(hdev, "2160p60hz420", 0);
432 if (vic != HDMI_0_UNKNOWN) {
433 printf("420,8bit\n");
434 goto next444;
435 }
436 vic = hdmitx_edid_get_VIC(hdev, "2160p50hz420", 0);
437 if (vic != HDMI_0_UNKNOWN) {
438 printf("420,8bit\n");
439 goto next444;
440 }
441 vic = hdmitx_edid_get_VIC(hdev, "smpte60hz420", 0);
442 if (vic != HDMI_0_UNKNOWN) {
443 printf("420,8bit\n");
444 goto next444;
445 }
446 vic = hdmitx_edid_get_VIC(hdev, "smpte50hz420", 0);
447 if (vic != HDMI_0_UNKNOWN) {
448 printf("420,8bit\n");
449 goto next444;
450 }
451 }
452next444:
453 if (prxcap->native_Mode & (1 << 5)) {
454 if (prxcap->dc_y444) {
455 if (prxcap->dc_36bit || dv->sup_10b_12b_444 == 0x2)
456 printf("444,12bit\n");
457 if (prxcap->dc_30bit || dv->sup_10b_12b_444 == 0x1)
458 printf("444,10bit\n");
459 }
460 printf("444,8bit\n");
461 }
462 /* y422, not check dc */
463 if (prxcap->native_Mode & (1 << 4)) {
464 printf("422,12bit\n");
465 printf("422,10bit\n");
466 printf("422,8bit\n");
467 }
468
469 if (prxcap->dc_36bit || dv->sup_10b_12b_444 == 0x2)
470 printf("rgb,12bit\n");
471 if (prxcap->dc_30bit || dv->sup_10b_12b_444 == 0x1)
472 printf("rgb,10bit\n");
473 printf("rgb,8bit\n");
474}
475
476static void aud_cap_show(struct hdmitx_dev *hdev)
477{
478}
479
480static void hdr_cap_show(struct hdmitx_dev *hdev)
481{
482 int hdr10plugsupported = 0;
483 struct hdr_info *hdr = &hdev->RXCap.hdr_info;
484 const struct hdr10_plus_info *hdr10p = &hdev->RXCap.hdr10plus_info;
485
486 printf("\nhdr_cap\n");
487 if (hdr10p->ieeeoui == HDR10_PLUS_IEEE_OUI &&
488 hdr10p->application_version != 0xFF)
489 hdr10plugsupported = 1;
490 printf("HDR10Plus Supported: %d\n", hdr10plugsupported);
491 printf("HDR Static Metadata:\n");
492 printf(" Supported EOTF:\n");
493 printf(" Traditional SDR: %d\n", !!hdr->hdr_sup_eotf_sdr);
494 printf(" Traditional HDR: %d\n", !!hdr->hdr_sup_eotf_hdr);
495 printf(" SMPTE ST 2084: %d\n", !!hdr->hdr_sup_eotf_smpte_st_2084);
496 printf(" Hybrid Log-Gamma: %d\n", !!hdr->hdr_sup_eotf_hlg);
497 printf(" Supported SMD type1: %d\n", hdr->hdr_sup_SMD_type1);
498 printf(" Luminance Data\n");
499 printf(" Max: %d\n", hdr->hdr_lum_max);
500 printf(" Avg: %d\n", hdr->hdr_lum_avg);
501 printf(" Min: %d\n\n", hdr->hdr_lum_min);
502 printf("HDR Dynamic Metadata:");
503}
504
505static void _dv_cap_show(const struct dv_info *dv)
506{
507 int i;
508
509 if (dv->ieeeoui != DV_IEEE_OUI || dv->block_flag != CORRECT) {
510 printf("The Rx don't support DolbyVision\n");
511 return;
512 }
513 printf("DolbyVision RX support list:\n");
514
515 if (dv->ver == 0) {
516 printf("VSVDB Version: V%d\n", dv->ver);
517 printf("2160p%shz: 1\n", dv->sup_2160p60hz ? "60" : "30");
518 printf("Support mode:\n");
519 printf(" DV_RGB_444_8BIT\n");
520 if (dv->sup_yuv422_12bit)
521 printf(" DV_YCbCr_422_12BIT\n");
522 }
523 if (dv->ver == 1) {
524 printf("VSVDB Version: V%d(%d-byte)\n", dv->ver, dv->length + 1);
525 if (dv->length == 0xB) {
526 printf("2160p%shz: 1\n", dv->sup_2160p60hz ? "60" : "30");
527 printf("Support mode:\n");
528 printf(" DV_RGB_444_8BIT\n");
529 if (dv->sup_yuv422_12bit)
530 printf(" DV_YCbCr_422_12BIT\n");
531 if (dv->low_latency == 0x01)
532 printf(" LL_YCbCr_422_12BIT\n");
533 }
534
535 if (dv->length == 0xE) {
536 printf("2160p%shz: 1\n", dv->sup_2160p60hz ? "60" : "30");
537 printf("Support mode:\n");
538 printf(" DV_RGB_444_8BIT\n");
539 if (dv->sup_yuv422_12bit)
540 printf(" DV_YCbCr_422_12BIT\n");
541 }
542 }
543 if (dv->ver == 2) {
544 printf("VSVDB Version: V%d\n", dv->ver);
545 printf("2160p%shz: 1\n", dv->sup_2160p60hz ? "60" : "30");
546 printf("Support mode:\n");
547 if (dv->Interface != 0x00 && dv->Interface != 0x01) {
548 printf(" DV_RGB_444_8BIT\n");
549 if (dv->sup_yuv422_12bit)
550 printf(" DV_YCbCr_422_12BIT\n");
551 }
552 printf(" LL_YCbCr_422_12BIT\n");
553 if (dv->Interface == 0x01 || dv->Interface == 0x03) {
554 if (dv->sup_10b_12b_444 == 0x1)
555 printf(" LL_RGB_444_10BIT\n");
556 if (dv->sup_10b_12b_444 == 0x2)
557 printf(" LL_RGB_444_12BIT\n");
558 }
559 }
560 printf("IEEEOUI: 0x%06x\n", dv->ieeeoui);
561 printf("VSVDB: ");
562 for (i = 0; i < (dv->length + 1); i++)
563 printf("%02x", dv->rawdata[i]);
564 printf("\n");
565}
566
567static void dv_cap_show(struct hdmitx_dev *hdev)
568{
569 const struct dv_info *dv = &hdev->RXCap.dv_info;
570
571 printf("dv_cap\n");
572 if (dv->ieeeoui != DV_IEEE_OUI) {
573 printf("The Rx don't support DolbyVision\n");
574 return;
575 }
576 _dv_cap_show(dv);
577}
578
579static void edid_cap_show(struct hdmitx_dev *hdev)
580{
581 int i;
582 struct rx_cap *prxcap = &hdev->RXCap;
583
584 printf("EDID Version: %d.%d\n", prxcap->edid_version, prxcap->edid_revision);
585
586 printf("EDID block number: 0x%x\n", hdev->rawedid[0x7e]);
587 printf("blk0 chksum: 0x%02x\n", prxcap->chksum);
588
589 printf("native Mode %x, VIC (native %d):\n",
590 prxcap->native_Mode, prxcap->native_VIC);
591
592 printf("ColorDeepSupport %x\n", prxcap->ColorDeepSupport);
593
594 for (i = 0 ; i < prxcap->VIC_count ; i++)
595 printf("%d ", prxcap->VIC[i]);
596 printf("\n");
597 printf("Vendor: 0x%x ( %s device)\n",
598 prxcap->IEEEOUI, (prxcap->IEEEOUI) ? "HDMI" : "DVI");
599
600 printf("MaxTMDSClock1 %d MHz\n", prxcap->Max_TMDS_Clock1 * 5);
601
602 if (prxcap->HF_IEEEOUI) {
603 printf("Vendor2: 0x%x\n", prxcap->HF_IEEEOUI);
604 printf("MaxTMDSClock2 %d MHz\n", prxcap->Max_TMDS_Clock2 * 5);
605 }
606
607 printf("Video_Latency: ");
608 if (prxcap->Video_Latency == 0)
609 printf(" Invalid/Unknown\n");
610 else if (prxcap->Video_Latency == 0xffff)
611 printf(" UnSupported\n");
612 else
613 printf(" %d\n", prxcap->Video_Latency);
614
615 printf("Audio_Latency: ");
616 if (prxcap->Audio_Latency == 0)
617 printf(" Invalid/Unknown\n");
618 else if (prxcap->Audio_Latency == 0xffff)
619 printf(" UnSupported\n");
620 else
621 printf(" %d\n", prxcap->Audio_Latency);
622
623 printf("Interlaced_Video_Latency: ");
624 if (prxcap->Interlaced_Video_Latency == 0)
625 printf(" Invalid/Unknown\n");
626 else if (prxcap->Interlaced_Video_Latency == 0xffff)
627 printf(" UnSupported\n");
628 else
629 printf(" %d\n", prxcap->Interlaced_Video_Latency);
630
631 printf("Interlaced_Audio_Latency: ");
632 if (prxcap->Interlaced_Audio_Latency == 0)
633 printf(" Invalid/Unknown\n");
634 else if (prxcap->Interlaced_Audio_Latency == 0xffff)
635 printf(" UnSupported\n");
636 else
637 printf(" %d\n", prxcap->Interlaced_Audio_Latency);
638
639 if (prxcap->colorimetry_data)
640 printf("ColorMetry: 0x%x\n", prxcap->colorimetry_data);
641 printf("SCDC: %x\n", prxcap->scdc_present);
642 printf("RR_Cap: %x\n", prxcap->scdc_rr_capable);
643 printf("LTE_340M_Scramble: %x\n", prxcap->lte_340mcsc_scramble);
644
645 if (prxcap->dv_info.ieeeoui == DV_IEEE_OUI)
646 printf(" DolbyVision%d", prxcap->dv_info.ver);
647 if (prxcap->hdr_info.hdr_sup_eotf_smpte_st_2084)
648 printf(" HDR/%d", prxcap->hdr_info.hdr_sup_eotf_smpte_st_2084);
649 if (prxcap->dc_y444 || prxcap->dc_30bit || prxcap->dc_30bit_420)
650 printf(" DeepColor");
651 printf("\n");
652}
653
654static int do_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
655{
656 struct hdmitx_dev *hdev = get_hdmitx21_device();
657 struct hdmi_format_para *para;
658
659 if (!hdev) {
660 pr_info("null hdmitx dev\n");
661 return CMD_RET_FAILURE;
662 }
663 if (!hdev->para) {
664 printf("null hdmitx para\n");
665 return CMD_RET_FAILURE;
666 }
667
668 para = hdev->para;
669 printf("current mode %s vic %d\n", para->timing.name, hdev->vic);
670 printf("cd%d cs%d cr%d\n", para->cd, para->cs, para->cr);
671 printf("enc_idx %d\n", hdev->enc_idx);
672 printf("frac_rate: %d\n", hdev->frac_rate_policy);
673 printf("Rx EDID info\n");
674 dump_full_edid(hdev->rawedid);
675 disp_cap_show(hdev);
676 vesa_cap_show(hdev);
677 aud_cap_show(hdev);
678 hdr_cap_show(hdev);
679 dv_cap_show(hdev);
680 dc_cap_show(hdev);
681 edid_cap_show(hdev);
682 return 1;
683}
684
685static int xtochar(int num, char *checksum)
686{
687 struct hdmitx_dev *hdev = get_hdmitx21_device();
688
689 if (((hdev->rawedid[num] >> 4) & 0xf) <= 9)
690 checksum[0] = ((hdev->rawedid[num] >> 4) & 0xf) + '0';
691 else
692 checksum[0] = ((hdev->rawedid[num] >> 4) & 0xf) - 10 + 'a';
693
694 if ((hdev->rawedid[num] & 0xf) <= 9)
695 checksum[1] = (hdev->rawedid[num] & 0xf) + '0';
696 else
697 checksum[1] = (hdev->rawedid[num] & 0xf) - 10 + 'a';
698
699 return 0;
700}
701
702static void get_parse_edid_data(struct hdmitx_dev *hdev)
703{
704 char *hdr_priority = env_get("hdr_priority");
705
706 hdev->hwop.read_edid(hdev->rawedid);
707
ruofei.zhao4a2ec0c2023-10-31 19:24:41 +0800708 /* dump edid raw data */
709 dump_full_edid(hdev->rawedid);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800710
711 /* parse edid data */
712 hdmi_edid_parsing(hdev->rawedid, &hdev->RXCap);
713
714 if (!hdr_priority)
715 return;
716 /* if hdr_priority is 2, then mark both dv_info and hdr_info */
717 if (strcmp(hdr_priority, "2") == 0) {
718 memset(&hdev->RXCap.dv_info, 0, sizeof(struct dv_info));
719 memset(&hdev->RXCap.hdr_info, 0, sizeof(struct hdr_info));
720 memset(&hdev->RXCap.hdr10plus_info, 0, sizeof(struct hdr10_plus_info));
721 pr_info("hdr_priority: %s and clear dv/hdr_info\n", hdr_priority);
722 return;
723 }
724 /* if hdr_priority is 1, then mark dv_info */
725 if (hdr_priority && (strcmp(hdr_priority, "1") == 0)) {
726 memset(&hdev->RXCap.dv_info, 0, sizeof(struct dv_info));
727 pr_info("hdr_priority: %s and clear dv_info\n", hdr_priority);
728 }
729}
730
731/* policy process: to find the output mode/attr/dv_type */
732void scene_process(struct hdmitx_dev *hdev,
733 struct scene_output_info *scene_output_info)
734{
735 struct input_hdmi_data hdmidata;
736
737 if (!hdev || !scene_output_info)
738 return;
739 /* 1.read dolby vision mode from prop(maybe need to env) */
740 memset(&hdmidata, 0, sizeof(struct input_hdmi_data));
741 get_hdmi_data(hdev, &hdmidata);
742
743 /* 2. dolby vision scene process */
744 /* only for tv support dv and box enable dv */
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800745 if (is_dv_preference(hdev)) {
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800746 dolbyvision_scene_process(&hdmidata, scene_output_info);
747 } else if (is_dolby_enabled()) {
748 /* for enable dolby vision core when
749 * first boot connecting non dv tv
750 * NOTE: let systemcontrol to enable DV core
751 */
752 /* scene_output_info->final_dv_type = DOLBY_VISION_ENABLE; */
753 } else {
754 /* for UI disable dolby vision core and boot keep the status
755 * NOTE: TBD if need to disable DV here
756 */
757 /* scene_output_info->final_dv_type = DOLBY_VISION_DISABLE; */
758 }
759 /* 3.sdr scene process */
760 /* decide final display mode and deepcolor */
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800761 if (is_dv_preference(hdev)) {
762 /* do nothing
763 * already done above, just sync with sysctrl
764 */
765 } else if (is_hdr_preference(hdev)) {
766 hdr_scene_process(&hdmidata, scene_output_info);
767 } else {
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800768 sdr_scene_process(&hdmidata, scene_output_info);
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800769 }
770 /* not find outputmode and use default mode */
771 if (strlen(scene_output_info->final_displaymode) == 0)
772 strcpy(scene_output_info->final_displaymode, DEFAULT_HDMI_MODE);
773 /* not find color space and use default mode */
774 if (!strstr(scene_output_info->final_deepcolor, "bit"))
775 strcpy(scene_output_info->final_deepcolor, DEFAULT_COLOR_FORMAT);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800776}
777
778static int do_get_parse_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
779{
780 struct hdmitx_dev *hdev = get_hdmitx21_device();
781 unsigned char *edid = hdev->rawedid;
782 unsigned char *store_checkvalue;
783
784 memset(edid, 0, EDID_BLK_SIZE * EDID_BLK_NO);
785 unsigned int i;
786 unsigned int checkvalue[4];
787 unsigned int checkvalue1;
788 unsigned int checkvalue2;
789 char checksum[11];
790 unsigned char def_cksum[] = {'0', 'x', '0', '0', '0', '0', '0', '0', '0', '0', '\0'};
791 char *hdmimode;
792 char *colorattribute;
793 char dv_type[2] = {0};
794 struct scene_output_info scene_output_info;
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800795 struct hdmi_format_para *para = NULL;
796 bool mode_support = false;
797 /* hdmi_mode / colorattribute may be null or "none".
798 * if either is null or "none", it means user not
799 * selected manually, and need to select the best
800 * mode or colorattribute by policy
801 */
802 bool no_manual_output = false;
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800803
804 if (!hdev->hwop.get_hpd_state()) {
805 printf("HDMI HPD low, no need parse EDID\n");
806 return 1;
807 }
808 memset(&scene_output_info, 0, sizeof(struct scene_output_info));
809
810 get_parse_edid_data(hdev);
811
812 /* check if the tv has changed or anything wrong */
813 store_checkvalue = (unsigned char *)env_get("hdmichecksum");
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800814 /* get user selected output mode/color */
815 colorattribute = env_get("user_colorattribute");
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800816 hdmimode = env_get("hdmimode");
817 if (!store_checkvalue)
818 store_checkvalue = def_cksum;
819
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800820 printf("read hdmichecksum: %s, user hdmimode: %s, colorattribute: %s\n",
821 store_checkvalue, hdmimode ? hdmimode : "null",
822 colorattribute ? colorattribute : "null");
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800823
824 for (i = 0; i < 4; i++) {
825 if (('0' <= store_checkvalue[i * 2 + 2]) && (store_checkvalue[i * 2 + 2] <= '9'))
826 checkvalue1 = store_checkvalue[i * 2 + 2] - '0';
827 else
828 checkvalue1 = store_checkvalue[i * 2 + 2] - 'W';
829 if (('0' <= store_checkvalue[i * 2 + 3]) && (store_checkvalue[i * 2 + 3] <= '9'))
830 checkvalue2 = store_checkvalue[i * 2 + 3] - '0';
831 else
832 checkvalue2 = store_checkvalue[i * 2 + 3] - 'W';
833 checkvalue[i] = checkvalue1 * 16 + checkvalue2;
834 }
835
836 if (checkvalue[0] != hdev->rawedid[0x7f] ||
837 checkvalue[1] != hdev->rawedid[0xff] ||
838 checkvalue[2] != hdev->rawedid[0x17f] ||
839 checkvalue[3] != hdev->rawedid[0x1ff]) {
840 hdev->RXCap.edid_changed = 1;
841
842 checksum[0] = '0';
843 checksum[1] = 'x';
844 for (i = 0; i < 4; i++)
845 xtochar(0x80 * i + 0x7f, &checksum[2 * i + 2]);
846 checksum[10] = '\0';
847 memcpy(hdev->RXCap.checksum, checksum, 10);
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800848 printf("TV has changed, now crc: %s\n", checksum);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800849 } else {
850 memcpy(hdev->RXCap.checksum, store_checkvalue, 10);
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800851 printf("TV is same, checksum: %s\n", hdev->RXCap.checksum);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800852 }
853
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800854 /* check user have selected both mode/color or not */
855 if (!hdmimode || !strcmp(hdmimode, "none") ||
856 !colorattribute || !strcmp(colorattribute, "none"))
857 no_manual_output = true;
858 else
859 no_manual_output = false;
860
861 if (!no_manual_output) {
862 /* check current user selected mode + color support or not */
863 para = hdmitx21_get_fmtpara(hdmimode, colorattribute);
864 if (hdmitx_edid_check_valid_mode(hdev, para))
865 mode_support = true;
866 else
867 mode_support = false;
868 }
869 /* three cases need to decide output by uboot mode select policy:
870 * 1.TV changed
871 * 2.either hdmimode or colorattribute is NULL or "none",
872 * which means that user have not selected mode or colorattribute,
873 * and need to select the auto best mode or best colorattribute.
874 * 3.user selected mode not supportted by uboot (probably
875 * means mode select policy or edid parse between sysctrl and
876 * uboot have some gap), then need to find proper output mode
877 * with uboot policy.
878 */
879 if (hdev->RXCap.edid_changed || no_manual_output || !mode_support) {
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800880 /* find proper mode if EDID changed */
881 scene_process(hdev, &scene_output_info);
882 env_set("hdmichecksum", hdev->RXCap.checksum);
883 if (edid_parsing_ok(hdev)) {
884 /* SWPL-34712: if EDID parsing error case, not save env,
885 * only output default mode(480p,RGB,8bit). after
886 * EDID read OK, systemcontrol will recover the hdmi
887 * mode from env, to avoid keep the default hdmi output
888 */
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800889 memcpy(sel_hdmimode, scene_output_info.final_displaymode,
890 sizeof(scene_output_info.final_displaymode));
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800891 if (is_hdmi_mode(env_get("outputmode"))) {
892 env_set("outputmode",
893 scene_output_info.final_displaymode);
894 } else if (is_hdmi_mode(env_get("outputmode2"))) {
895 env_set("outputmode2",
896 scene_output_info.final_displaymode);
897 } else if (is_hdmi_mode(env_get("outputmode3"))) {
898 env_set("outputmode3",
899 scene_output_info.final_displaymode);
900 }
901 env_set("colorattribute",
902 scene_output_info.final_deepcolor);
903 /* if change from DV TV to HDR/SDR TV, don't change
904 * DV status to disabled, as DV core need to be enabled.
905 */
906 if (scene_output_info.final_dv_type != get_ubootenv_dv_type() &&
907 scene_output_info.final_dv_type != DOLBY_VISION_DISABLE) {
908 sprintf(dv_type, "%d", scene_output_info.final_dv_type);
909 env_set("dolby_status", dv_type);
910 /* according to the policy of systemcontrol,
911 * if current DV mode is not supported by TV
912 * EDID, DV type maybe changed to one witch
913 * TV support, and need VPP/DV module to
914 * update new DV output mode.
915 */
916 printf("update dv_type: %d\n",
917 scene_output_info.final_dv_type);
918 }
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800919 } else {
920 save_default_720p();
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800921 }
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800922 printf("update outputmode: %s\n", sel_hdmimode);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800923 printf("update colorattribute: %s\n", env_get("colorattribute"));
924 printf("update hdmichecksum: %s\n", env_get("hdmichecksum"));
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800925 } else {
926 memset(sel_hdmimode, 0, sizeof(sel_hdmimode));
927 memcpy(sel_hdmimode, hdmimode, strlen(hdmimode));
928 if (is_hdmi_mode(env_get("outputmode")))
929 env_set("outputmode", hdmimode);
930 else if (is_hdmi_mode(env_get("outputmode2")))
931 env_set("outputmode2", hdmimode);
932 else if (is_hdmi_mode(env_get("outputmode3")))
933 env_set("outputmode3", hdmimode);
934 env_set("colorattribute", colorattribute);
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800935 }
Wenjie Qiao389d3ea2023-05-25 16:07:03 +0800936 hdev->para = hdmitx21_get_fmtpara(sel_hdmimode, env_get("colorattribute"));
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800937 hdev->vic = hdev->para->timing.vic;
938 hdmitx_mask_rx_info(hdev);
939 return 0;
940}
941
Wenjie Qiao77833902023-12-18 19:01:59 +0800942#ifdef CONFIG_EFUSE_OBJ_API
943static int do_efuse_show(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
944{
945 struct hdmitx_dev *hdev = get_hdmitx21_device();
946
947 get_hdmi_efuse(hdev);
948 pr_info("FEAT_DISABLE_HDMI_60HZ = %d\n", hdev->efuse_dis_hdmi_4k60);
949 pr_info("FEAT_DISABLE_OUTPUT_4K = %d\n", hdev->efuse_dis_output_4k);
950 pr_info("FEAT_DISABLE_HDCP_TX_22 = %d\n", hdev->efuse_dis_hdcp_tx22);
951 pr_info("FEAT_DISABLE_HDMI_TX_3D = %d\n", hdev->efuse_dis_hdmi_tx3d);
952 pr_info("FEAT_DISABLE_HDMI = %d\n", hdev->efuse_dis_hdcp_tx14);
953
954 return 0;
955}
956#endif
957
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800958static cmd_tbl_t cmd_hdmi_sub[] = {
959 U_BOOT_CMD_MKENT(hpd, 1, 1, do_hpd_detect, "", ""),
960 U_BOOT_CMD_MKENT(edid, 3, 1, do_edid, "", ""),
961 U_BOOT_CMD_MKENT(rx_det, 1, 1, do_rx_det, "", ""),
962 U_BOOT_CMD_MKENT(output, 3, 1, do_output, "", ""),
963 U_BOOT_CMD_MKENT(clkmsr, 3, 1, do_clkmsr, "", ""),
964 U_BOOT_CMD_MKENT(blank, 3, 1, do_blank, "", ""),
965 U_BOOT_CMD_MKENT(off, 1, 1, do_off, "", ""),
966 U_BOOT_CMD_MKENT(dump, 1, 1, do_dump, "", ""),
967 U_BOOT_CMD_MKENT(info, 1, 1, do_info, "", ""),
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800968 U_BOOT_CMD_MKENT(reg, 3, 1, do_reg, "", ""),
969 U_BOOT_CMD_MKENT(get_parse_edid, 1, 1, do_get_parse_edid, "", ""),
Wenjie Qiao77833902023-12-18 19:01:59 +0800970#ifdef CONFIG_EFUSE_OBJ_API
971 U_BOOT_CMD_MKENT(efuse, 1, 1, do_efuse_show, "", ""),
972#endif
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800973};
974
975static int do_hdmitx(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
976{
977 cmd_tbl_t *c;
978
979 if (argc < 2)
980 return cmd_usage(cmdtp);
981
982 argc--;
983 argv++;
984
985 c = find_cmd_tbl(argv[0], &cmd_hdmi_sub[0], ARRAY_SIZE(cmd_hdmi_sub));
986
987 if (c)
988 return c->cmd(cmdtp, flag, argc, argv);
989 else
990 return cmd_usage(cmdtp);
991}
992
993U_BOOT_CMD(hdmitx, CONFIG_SYS_MAXARGS, 0, do_hdmitx,
994 "HDMITX sub-system",
995 "hdmitx version:20200618\n"
996 "hdmitx hpd\n"
997 " Detect hdmi rx plug-in\n"
Wenjie Qiao8a73a562023-02-23 18:37:14 +0800998 "hdmitx output [list | FORMAT | bist PATTERN]\n"
999 " list: list support formats\n"
1000 " FORMAT can be 720p60/50hz, 1080i60/50hz, 1080p60hz, etc\n"
1001 " extend with 8bits/10bits, y444/y422/y420/rgb\n"
1002 " such as 2160p60hz,10bits,y420\n"
1003 " PATTERN: can be as: line, dot, off, or 1920(width)\n"
1004 "hdmitx blank [0|1]\n"
1005 " 1: output blank 0: output normal\n"
1006 "hdmitx clkmsr\n"
1007 " show hdmitx clocks\n"
1008 "hdmitx off\n"
1009 " Turn off hdmitx output\n"
1010 "hdmitx info\n"
1011 " current mode info\n"
1012 "hdmitx rx_det\n"
1013 " Auto detect if RX is FBC and set outputmode\n"
1014);
1015
1016struct hdr_info *hdmitx_get_rx_hdr_info(void)
1017{
1018 struct hdmitx_dev *hdev = get_hdmitx21_device();
1019
1020 return &hdev->RXCap.hdr_info;
1021}