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 10zx_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