1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <ddk/debug.h>
6 
7 #include "vim-display.h"
8 #include "edid.h"
9 
get_vic(const display_mode_t * disp_timing,struct hdmi_param * p)10 zx_status_t get_vic(const display_mode_t* disp_timing, struct hdmi_param* p)
11 {
12     // Monitor has its own preferred timings. Use that
13     p->timings.interlace_mode =     disp_timing->flags & MODE_FLAG_INTERLACED;
14     p->timings.pfreq =              (disp_timing->pixel_clock_10khz * 10); // KHz
15     //TODO: pixel repetition is 0 for most progressive. We don't support interlaced
16     p->timings.pixel_repeat =       0;
17     p->timings.hactive =            disp_timing->h_addressable;
18     p->timings.hblank =             disp_timing->h_blanking;
19     p->timings.hfront =             disp_timing->h_front_porch;
20     p->timings.hsync =              disp_timing->h_sync_pulse;
21     p->timings.htotal =             (p->timings.hactive) + (p->timings.hblank);
22     p->timings.hback =              (p->timings.hblank) - (p->timings.hfront + p->timings.hsync);
23     p->timings.hpol =               disp_timing->flags & MODE_FLAG_HSYNC_POSITIVE;
24 
25     p->timings.vactive =            disp_timing->v_addressable;
26     p->timings.vblank0 =            disp_timing->v_blanking;
27     p->timings.vfront =             disp_timing->v_front_porch;
28     p->timings.vsync =              disp_timing->v_sync_pulse;
29     p->timings.vtotal =             (p->timings.vactive) + (p->timings.vblank0);
30     p->timings.vback =              (p->timings.vblank0) - (p->timings.vfront + p->timings.vsync);
31     p->timings.vpol =               disp_timing->flags & MODE_FLAG_VSYNC_POSITIVE;
32 
33     //FIXE: VENC Repeat is undocumented. It seems to be only needed for the following
34     // resolutions: 1280x720p60, 1280x720p50, 720x480p60, 720x480i60, 720x576p50, 720x576i50
35     // For now, we will simply not support this feature.
36     p->timings.venc_pixel_repeat = 0;
37     // Let's make sure we support what we've got so far
38     if (p->timings.interlace_mode) {
39         return ZX_ERR_NOT_SUPPORTED;
40     }
41 
42     if (p->timings.vactive == 2160) {
43         DISP_INFO("4K Monitor Detected.\n");
44 
45         if (p->timings.pfreq == 533250) {
46             // FIXME: 4K with reduced blanking (533.25MHz) does not work
47             DISP_INFO("4K @ 30Hz\n");
48             p->timings.interlace_mode =     0;
49             p->timings.pfreq =              (297000); // KHz
50             p->timings.pixel_repeat =       0;
51             p->timings.hactive =            3840;
52             p->timings.hblank =             560;
53             p->timings.hfront =             176;
54             p->timings.hsync =              88;
55             p->timings.htotal =             (p->timings.hactive) + (p->timings.hblank);
56             p->timings.hback =              (p->timings.hblank) -
57                                                (p->timings.hfront + p->timings.hsync);
58             p->timings.hpol =               1;
59             p->timings.vactive =            2160;
60             p->timings.vblank0 =            90;
61             p->timings.vfront =             8;
62             p->timings.vsync =              10;
63             p->timings.vtotal =             (p->timings.vactive) + (p->timings.vblank0);
64             p->timings.vback =              (p->timings.vblank0) -
65                                                (p->timings.vfront + p->timings.vsync);
66             p->timings.vpol =               1;
67         }
68     }
69 
70     if (p->timings.pfreq > 500000) {
71         p->is4K = true;
72     } else {
73         p->is4K = false;
74     }
75 
76     if (p->timings.hactive * 3 == p->timings.vactive * 4) {
77         p->aspect_ratio = HDMI_ASPECT_RATIO_4x3;
78     } else if (p->timings.hactive * 9 == p->timings.vactive * 16) {
79         p->aspect_ratio = HDMI_ASPECT_RATIO_16x9;
80     } else {
81         p->aspect_ratio = HDMI_ASPECT_RATIO_NONE;
82     }
83 
84     p->colorimetry = HDMI_COLORIMETRY_ITU601;
85 
86     if (p->timings.pfreq > 500000) {
87         p->phy_mode = 1;
88     } else if (p->timings.pfreq > 200000) {
89         p->phy_mode = 2;
90     } else if (p->timings.pfreq > 100000) {
91         p->phy_mode = 3;
92     } else {
93         p->phy_mode = 4;
94     }
95 
96     //TODO: We probably need a more sophisticated method for calculating
97     // clocks. This will do for now.
98     p->pll_p_24b.viu_channel =          1;
99     p->pll_p_24b.viu_type =             VIU_ENCP;
100     p->pll_p_24b.vid_pll_div =          VID_PLL_DIV_5;
101     p->pll_p_24b.vid_clk_div =          2;
102     p->pll_p_24b.hdmi_tx_pixel_div =    1;
103     p->pll_p_24b.encp_div =             1;
104     p->pll_p_24b.od1 =                  1;
105     p->pll_p_24b.od2 =                  1;
106     p->pll_p_24b.od3 =                  1;
107 
108     p->pll_p_24b.hpll_clk_out = (p->timings.pfreq * 10);
109     while (p->pll_p_24b.hpll_clk_out < 2900000) {
110         if (p->pll_p_24b.od1 < 4) {
111             p->pll_p_24b.od1 *= 2;
112             p->pll_p_24b.hpll_clk_out *= 2;
113         } else if (p->pll_p_24b.od2 < 4) {
114             p->pll_p_24b.od2 *= 2;
115             p->pll_p_24b.hpll_clk_out *= 2;
116         } else if (p->pll_p_24b.od3 < 4) {
117             p->pll_p_24b.od3 *= 2;
118             p->pll_p_24b.hpll_clk_out *= 2;
119         } else {
120             return ZX_ERR_OUT_OF_RANGE;
121         }
122     }
123     if(p->pll_p_24b.hpll_clk_out > 6000000) {
124         DISP_ERROR("Something went wrong in clock calculation (pll_out = %d)\n",
125             p->pll_p_24b.hpll_clk_out);
126         return ZX_ERR_OUT_OF_RANGE;
127     }
128 
129     return ZX_OK;
130 }
131