blob: 94062513537aca30f1c4978f14adb1ae59271700 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ddk/debug.h>
#include "vim-display.h"
#include "edid.h"
zx_status_t get_vic(const display_mode_t* disp_timing, struct hdmi_param* p)
{
// Monitor has its own preferred timings. Use that
p->timings.interlace_mode = disp_timing->flags & MODE_FLAG_INTERLACED;
p->timings.pfreq = (disp_timing->pixel_clock_10khz * 10); // KHz
//TODO: pixel repetition is 0 for most progressive. We don't support interlaced
p->timings.pixel_repeat = 0;
p->timings.hactive = disp_timing->h_addressable;
p->timings.hblank = disp_timing->h_blanking;
p->timings.hfront = disp_timing->h_front_porch;
p->timings.hsync = disp_timing->h_sync_pulse;
p->timings.htotal = (p->timings.hactive) + (p->timings.hblank);
p->timings.hback = (p->timings.hblank) - (p->timings.hfront + p->timings.hsync);
p->timings.hpol = disp_timing->flags & MODE_FLAG_HSYNC_POSITIVE;
p->timings.vactive = disp_timing->v_addressable;
p->timings.vblank0 = disp_timing->v_blanking;
p->timings.vfront = disp_timing->v_front_porch;
p->timings.vsync = disp_timing->v_sync_pulse;
p->timings.vtotal = (p->timings.vactive) + (p->timings.vblank0);
p->timings.vback = (p->timings.vblank0) - (p->timings.vfront + p->timings.vsync);
p->timings.vpol = disp_timing->flags & MODE_FLAG_VSYNC_POSITIVE;
//FIXE: VENC Repeat is undocumented. It seems to be only needed for the following
// resolutions: 1280x720p60, 1280x720p50, 720x480p60, 720x480i60, 720x576p50, 720x576i50
// For now, we will simply not support this feature.
p->timings.venc_pixel_repeat = 0;
// Let's make sure we support what we've got so far
if (p->timings.interlace_mode) {
return ZX_ERR_NOT_SUPPORTED;
}
if (p->timings.vactive == 2160) {
DISP_INFO("4K Monitor Detected.\n");
if (p->timings.pfreq == 533250) {
// FIXME: 4K with reduced blanking (533.25MHz) does not work
DISP_INFO("4K @ 30Hz\n");
p->timings.interlace_mode = 0;
p->timings.pfreq = (297000); // KHz
p->timings.pixel_repeat = 0;
p->timings.hactive = 3840;
p->timings.hblank = 560;
p->timings.hfront = 176;
p->timings.hsync = 88;
p->timings.htotal = (p->timings.hactive) + (p->timings.hblank);
p->timings.hback = (p->timings.hblank) -
(p->timings.hfront + p->timings.hsync);
p->timings.hpol = 1;
p->timings.vactive = 2160;
p->timings.vblank0 = 90;
p->timings.vfront = 8;
p->timings.vsync = 10;
p->timings.vtotal = (p->timings.vactive) + (p->timings.vblank0);
p->timings.vback = (p->timings.vblank0) -
(p->timings.vfront + p->timings.vsync);
p->timings.vpol = 1;
}
}
if (p->timings.pfreq > 500000) {
p->is4K = true;
} else {
p->is4K = false;
}
if (p->timings.hactive * 3 == p->timings.vactive * 4) {
p->aspect_ratio = HDMI_ASPECT_RATIO_4x3;
} else if (p->timings.hactive * 9 == p->timings.vactive * 16) {
p->aspect_ratio = HDMI_ASPECT_RATIO_16x9;
} else {
p->aspect_ratio = HDMI_ASPECT_RATIO_NONE;
}
p->colorimetry = HDMI_COLORIMETRY_ITU601;
if (p->timings.pfreq > 500000) {
p->phy_mode = 1;
} else if (p->timings.pfreq > 200000) {
p->phy_mode = 2;
} else if (p->timings.pfreq > 100000) {
p->phy_mode = 3;
} else {
p->phy_mode = 4;
}
//TODO: We probably need a more sophisticated method for calculating
// clocks. This will do for now.
p->pll_p_24b.viu_channel = 1;
p->pll_p_24b.viu_type = VIU_ENCP;
p->pll_p_24b.vid_pll_div = VID_PLL_DIV_5;
p->pll_p_24b.vid_clk_div = 2;
p->pll_p_24b.hdmi_tx_pixel_div = 1;
p->pll_p_24b.encp_div = 1;
p->pll_p_24b.od1 = 1;
p->pll_p_24b.od2 = 1;
p->pll_p_24b.od3 = 1;
p->pll_p_24b.hpll_clk_out = (p->timings.pfreq * 10);
while (p->pll_p_24b.hpll_clk_out < 2900000) {
if (p->pll_p_24b.od1 < 4) {
p->pll_p_24b.od1 *= 2;
p->pll_p_24b.hpll_clk_out *= 2;
} else if (p->pll_p_24b.od2 < 4) {
p->pll_p_24b.od2 *= 2;
p->pll_p_24b.hpll_clk_out *= 2;
} else if (p->pll_p_24b.od3 < 4) {
p->pll_p_24b.od3 *= 2;
p->pll_p_24b.hpll_clk_out *= 2;
} else {
return ZX_ERR_OUT_OF_RANGE;
}
}
if(p->pll_p_24b.hpll_clk_out > 6000000) {
DISP_ERROR("Something went wrong in clock calculation (pll_out = %d)\n",
p->pll_p_24b.hpll_clk_out);
return ZX_ERR_OUT_OF_RANGE;
}
return ZX_OK;
}