blob: 0704d6d73c931b17459ee68a0eca016caa66dd65 [file] [log] [blame]
// Copyright 2022 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 "src/graphics/display/drivers/intel-i915/dpll-config.h"
#include <cstdint>
#include <optional>
#include <gtest/gtest.h>
#include "src/graphics/display/drivers/intel-i915/dpll.h"
#include "src/graphics/display/drivers/intel-i915/hardware-common.h"
#include "src/graphics/display/drivers/intel-i915/registers-dpll.h"
namespace i915 {
namespace {
TEST(CreateDpllFrequencyDividerConfigKabyLakeTest, AllDivisors) {
for (const int8_t& divider : DpllSupportedFrequencyDividersKabyLake()) {
SCOPED_TRACE(testing::Message() << "Divider: " << int{divider});
const DpllFrequencyDividerConfig divider_config =
CreateDpllFrequencyDividerConfigKabyLake(divider);
EXPECT_EQ(divider, divider_config.p0_p_divider * divider_config.p1_q_divider *
divider_config.p2_k_divider);
EXPECT_GT(divider_config.p0_p_divider, 0);
EXPECT_GT(divider_config.p1_q_divider, 0);
EXPECT_GT(divider_config.p2_k_divider, 0);
// The helpers below ZX_DEBUG_ASSERT() on incorrect divider values. The
// assignments are on separate lines to facilitate debugging.
auto dpll_config2 =
registers::DisplayPllDcoDividersKabyLake::GetForDpll(PllId::DPLL_1).FromValue(0);
dpll_config2.set_p_p0_divider(static_cast<uint8_t>(divider_config.p0_p_divider));
dpll_config2.set_q_p1_divider(static_cast<uint8_t>(divider_config.p1_q_divider));
dpll_config2.set_k_p2_divider(static_cast<uint8_t>(divider_config.p2_k_divider));
}
}
TEST(CreateDpllFrequencyDividerConfigKabyLakeTest, PrmExample1) {
// Values from IHD-OS-KBL-Vol 12-1.17 section "Example of DVI on DDIB using
// 113.309 MHz symbol "clock", page 137.
const DpllFrequencyDividerConfig divider_config = CreateDpllFrequencyDividerConfigKabyLake(16);
EXPECT_EQ(2, divider_config.p0_p_divider);
EXPECT_EQ(4, divider_config.p1_q_divider);
EXPECT_EQ(2, divider_config.p2_k_divider);
}
TEST(CreateDpllFrequencyDividerConfigKabyLakeTest, PrmExample2) {
// Values from IHD-OS-KBL-Vol 12-1.17 section "Example of HDMI on DDIC using
// 296.703 MHz symbol clock", pages 137-138.
//
// The K (P2) and P (P0) divisor values don't match the PRM values. The PRM
// states "P0 = 1, P1 = 3, P2 = 2" in the summary, and then "P1 = 1",
// "Kdiv = P2 = 01b (2)", "Pdiv = P0 = 010b (3)" in the DPLL2_CFGCR2
// breakdown.
//
// The getMultiplier(num) pseudocode produces P0 = 2, P1 = 1, P2 = 3 because
// num % 2 == 0 and num1 (in the first if branch) == 3. The pseudocode matches
// the OpenBSD i915 driver code.
const DpllFrequencyDividerConfig divider_config = CreateDpllFrequencyDividerConfigKabyLake(6);
EXPECT_EQ(2, divider_config.p0_p_divider);
EXPECT_EQ(1, divider_config.p1_q_divider);
EXPECT_EQ(3, divider_config.p2_k_divider);
}
TEST(CreateDpllFrequencyDividerConfigTigerLakeTest, AllDivisors) {
for (const int8_t& divider : DpllSupportedFrequencyDividersTigerLake()) {
SCOPED_TRACE(testing::Message() << "Divider: " << int{divider});
const DpllFrequencyDividerConfig divider_config =
CreateDpllFrequencyDividerConfigTigerLake(divider);
EXPECT_EQ(divider, divider_config.p0_p_divider * divider_config.p1_q_divider *
divider_config.p2_k_divider);
EXPECT_GT(divider_config.p0_p_divider, 0);
EXPECT_GT(divider_config.p1_q_divider, 0);
EXPECT_GT(divider_config.p2_k_divider, 0);
// The helpers below ZX_DEBUG_ASSERT() on incorrect divider values. The
// assignments are on separate lines to facilitate debugging.
auto pll_dco_dividers =
registers::DisplayPllDcoDividersTigerLake::GetForDpll(PllId::DPLL_0).FromValue(0);
pll_dco_dividers.set_p_p0_divider(static_cast<uint8_t>(divider_config.p0_p_divider));
pll_dco_dividers.set_q_p1_divider(static_cast<uint8_t>(divider_config.p1_q_divider));
pll_dco_dividers.set_k_p2_divider(static_cast<uint8_t>(divider_config.p2_k_divider));
}
}
TEST(CreateDpllFrequencyDividerConfigTigerLakeTest, PrmExample1) {
// Values from IHD-OS-TGL-Vol 12-1.22-Rev2.0 section "Example of DVI on DDIB
// using 113.309 MHz symbol clock and reference 24 MHz", page 182.
const DpllFrequencyDividerConfig divider_config = CreateDpllFrequencyDividerConfigTigerLake(16);
EXPECT_EQ(2, divider_config.p0_p_divider);
EXPECT_EQ(4, divider_config.p1_q_divider);
EXPECT_EQ(2, divider_config.p2_k_divider);
}
TEST(CreateDpllFrequencyDividerConfigTigerLakeTest, PrmExample2) {
// Values from IHD-OS-TGL-Vol 12-1.22-Rev2.0 section "Example for DSI0 8X
// 556.545 and reference 24 MHz", pages 185-186.
const DpllFrequencyDividerConfig divider_config = CreateDpllFrequencyDividerConfigTigerLake(3);
EXPECT_EQ(3, divider_config.p0_p_divider);
EXPECT_EQ(1, divider_config.p1_q_divider);
EXPECT_EQ(1, divider_config.p2_k_divider);
}
TEST(CreateDpllFrequencyDividerConfigTigerLakeTest, DisplayPortTable) {
// Test cases from IHD-OS-TGL-Vol 12-1.22-Rev2.0 section "DisplayPort Mode PLL
// Values" pages 178-179.
struct TableRow {
int8_t p, k, q;
};
static constexpr TableRow kTableRows[] = {
{.p = 3, .k = 1, .q = 1}, {.p = 3, .k = 2, .q = 1}, {.p = 5, .k = 2, .q = 1},
{.p = 5, .k = 1, .q = 1}, {.p = 2, .k = 2, .q = 2}, {.p = 2, .k = 2, .q = 1},
{.p = 2, .k = 1, .q = 1},
};
for (const TableRow& test_row : kTableRows) {
const int8_t divider = static_cast<int8_t>(int{test_row.p} * int{test_row.k} * int{test_row.q});
SCOPED_TRACE(testing::Message() << "Divider: " << int{divider});
const DpllFrequencyDividerConfig divider_config =
CreateDpllFrequencyDividerConfigTigerLake(divider);
EXPECT_EQ(test_row.p, divider_config.p0_p_divider);
EXPECT_EQ(test_row.k, divider_config.p2_k_divider);
EXPECT_EQ(test_row.q, divider_config.p1_q_divider);
}
}
TEST(CreateDpllOscillatorConfigKabyLakeTest, PrmExample1) {
// Values from IHD-OS-KBL-Vol 12-1.17 section "Example of DVI on DDIB using
// 113.309 MHz symbol "clock", page 137.
const DpllOscillatorConfig dco_config = CreateDpllOscillatorConfigKabyLake(113'309 * 5);
EXPECT_EQ(9'000'000, dco_config.center_frequency_khz);
EXPECT_EQ(16, dco_config.frequency_divider);
EXPECT_EQ(113'309 * 5 * 16, dco_config.frequency_khz);
}
TEST(CreateDpllOscillatorConfigKabyLakeTest, PrmExample2) {
// Values from IHD-OS-KBL-Vol 12-1.17 section "Example of HDMI on DDIC using
// 296.703 MHz symbol clock", pages 137-138.
const DpllOscillatorConfig dco_config = CreateDpllOscillatorConfigKabyLake(296'703 * 5);
EXPECT_EQ(9'000'000, dco_config.center_frequency_khz);
EXPECT_EQ(6, dco_config.frequency_divider);
EXPECT_EQ(296'703 * 5 * 6, dco_config.frequency_khz);
}
TEST(CreateDpllOscillatorConfigForHdmiTigerLakeTest, PrmExample1) {
// Values from IHD-OS-TGL-Vol 12-1.22-Rev2.0 section "Example of DVI on DDIB
// using 113.309 MHz symbol clock and reference 24 MHz", page 182.
const DpllOscillatorConfig dco_config = CreateDpllOscillatorConfigForHdmiTigerLake(113'309 * 5);
EXPECT_EQ(8'999'000, dco_config.center_frequency_khz);
EXPECT_EQ(16, dco_config.frequency_divider);
EXPECT_EQ(9'064'720, dco_config.frequency_khz);
}
TEST(CreateDpllOscillatorConfigForHdmiTigerLakeTest, PrmExample2) {
// Values from IHD-OS-TGL-Vol 12-1.22-Rev2.0 section "Example for DSI0 8X
// 556.545 and reference 24 MHz", pages 185-186.
const DpllOscillatorConfig dco_config = CreateDpllOscillatorConfigForHdmiTigerLake(566'545 * 5);
EXPECT_EQ(8'999'000, dco_config.center_frequency_khz);
EXPECT_EQ(3, dco_config.frequency_divider);
EXPECT_EQ(8'498'175, dco_config.frequency_khz);
}
TEST(CreateDpllOscillatorConfigForHdmiTigerLakeTest, DisplayPortTable) {
// Test cases from IHD-OS-TGL-Vol 12-1.22-Rev2.0 section "DisplayPort Mode PLL
// Values" pages 178-179.
struct TableRow {
int32_t link_rate_khz;
int32_t frequency;
int8_t divider;
};
static constexpr TableRow kTableRows[] = {
// The algorithm solutions match the table for the cases below.
{.link_rate_khz = 5'400'000, .frequency = 8'100'000, .divider = 3},
{.link_rate_khz = 2'160'000, .frequency = 8'640'000, .divider = 8},
{.link_rate_khz = 4'320'000, .frequency = 8'640'000, .divider = 4},
{.link_rate_khz = 6'480'000, .frequency = 9'720'000, .divider = 3},
{.link_rate_khz = 8'100'000, .frequency = 8'100'000, .divider = 2},
// The algorithm finds different values from the table. The solutions
// here are better than the table's solutions in respect to the
// algorithm's stated goal of minimizing DCO frequency deviation from the
// centrer frequency.
{.link_rate_khz = 2'700'000, .frequency = 9'450'000, .divider = 7},
{.link_rate_khz = 1'620'000, .frequency = 9'720'000, .divider = 12},
{.link_rate_khz = 3'240'000, .frequency = 9'720'000, .divider = 6},
};
for (const TableRow& test_row : kTableRows) {
const int32_t afe_clock_khz = static_cast<int32_t>(test_row.link_rate_khz / 2);
SCOPED_TRACE(testing::Message()
<< "Link rate: " << test_row.link_rate_khz << " kHz AFE clock: " << afe_clock_khz);
const DpllOscillatorConfig dco_config =
CreateDpllOscillatorConfigForHdmiTigerLake(afe_clock_khz);
EXPECT_EQ(8'999'000, dco_config.center_frequency_khz);
EXPECT_EQ(test_row.frequency, dco_config.frequency_khz);
EXPECT_EQ(test_row.divider, dco_config.frequency_divider);
}
}
TEST(CreateDpllOscillatorConfigForDisplayPortTigerLakeTest, DisplayPortTable) {
// Test cases from IHD-OS-TGL-Vol 12-1.22-Rev2.0 section "DisplayPort Mode PLL
// Values" pages 178-179.
struct TableRow {
int32_t link_rate_khz;
int32_t frequency;
int8_t divider;
};
static constexpr TableRow kTableRows[] = {
// The algorithm solutions match the table for the cases below.
{.link_rate_khz = 5'400'000, .frequency = 8'100'000, .divider = 3},
{.link_rate_khz = 2'700'000, .frequency = 8'100'000, .divider = 6},
{.link_rate_khz = 1'620'000, .frequency = 8'100'000, .divider = 10},
{.link_rate_khz = 3'240'000, .frequency = 8'100'000, .divider = 5},
{.link_rate_khz = 2'160'000, .frequency = 8'640'000, .divider = 8},
{.link_rate_khz = 4'320'000, .frequency = 8'640'000, .divider = 4},
{.link_rate_khz = 6'480'000, .frequency = 9'720'000, .divider = 3},
{.link_rate_khz = 8'100'000, .frequency = 8'100'000, .divider = 2},
};
for (const TableRow& test_row : kTableRows) {
const int32_t afe_clock_khz = static_cast<int32_t>(test_row.link_rate_khz / 2);
SCOPED_TRACE(testing::Message()
<< "Link rate: " << test_row.link_rate_khz << " kHz AFE clock: " << afe_clock_khz);
const DpllOscillatorConfig dco_config =
CreateDpllOscillatorConfigForDisplayPortTigerLake(afe_clock_khz);
EXPECT_EQ(8'999'000, dco_config.center_frequency_khz);
EXPECT_EQ(test_row.frequency, dco_config.frequency_khz);
EXPECT_EQ(test_row.divider, dco_config.frequency_divider);
}
}
} // namespace
} // namespace i915