blob: cb386fee86b2262130a412dd3e9bd463b67c2f23 [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/ddi-physical-layer.h"
#include <lib/mmio/mmio-buffer.h>
#include <fake-mmio-reg/fake-mmio-reg.h>
#include <gtest/gtest.h>
#include <mock-mmio-range/mock-mmio-range.h>
#include "src/graphics/display/drivers/intel-i915/ddi-physical-layer-internal.h"
#include "src/graphics/display/drivers/intel-i915/hardware-common.h"
#include "src/graphics/display/drivers/intel-i915/registers-typec.h"
namespace i915 {
namespace {
const std::unordered_map<PowerWellId, PowerWellInfo> kPowerWellInfoTestDevice = {};
// A fake power well implementation used only for integration tests.
class TestPower : public Power {
public:
explicit TestPower(fdf::MmioBuffer* mmio_space) : Power(mmio_space, &kPowerWellInfoTestDevice) {}
void Resume() override {}
PowerWellRef GetCdClockPowerWellRef() override { return PowerWellRef(); }
PowerWellRef GetPipePowerWellRef(PipeId pipe_id) override { return PowerWellRef(); }
PowerWellRef GetDdiPowerWellRef(DdiId ddi_id) override { return PowerWellRef(); }
bool GetDdiIoPowerState(DdiId ddi_id) override { return true; }
void SetDdiIoPowerState(DdiId ddi_id, bool enable) override {}
bool GetAuxIoPowerState(DdiId ddi_id) override {
if (aux_state_.find(ddi_id) == aux_state_.end()) {
aux_state_[ddi_id] = false;
}
return aux_state_[ddi_id];
}
void SetAuxIoPowerState(DdiId ddi_id, bool enable) override { aux_state_[ddi_id] = enable; }
private:
void SetPowerWell(PowerWellId power_well, bool enable) override {}
std::unordered_map<DdiId, bool> aux_state_;
};
class TypeCDdiTigerLakeTest : public ::testing::Test {
public:
TypeCDdiTigerLakeTest() = default;
protected:
constexpr static int kMmioRangeSize = 0x200000;
ddk_mock::MockMmioRange mmio_range_{kMmioRangeSize, ddk_mock::MockMmioRange::Size::k32};
fdf::MmioBuffer mmio_buffer_{mmio_range_.GetMmioBuffer()};
TestPower power_{nullptr};
};
constexpr uint32_t kMailboxInterfaceOffset = 0x138124;
constexpr uint32_t kMailboxData0Offset = 0x138128;
constexpr uint32_t kMailboxData1Offset = 0x13812c;
TEST_F(TypeCDdiTigerLakeTest, EnableFsm_TypeCColdBlock_Success) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kMailboxInterfaceOffset, .value = 0},
{.address = kMailboxData0Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxData1Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x8000'0026, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x0000'0026},
// The Type-C subsystem has exited TCCOLD.
{.address = kMailboxData0Offset, .value = 0x0000'0000},
{.address = kMailboxData1Offset, .value = 0x0000'0000},
}));
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_, /*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kUninitialized);
EXPECT_TRUE(ddi.AdvanceEnableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
}
TEST_F(TypeCDdiTigerLakeTest, EnableFsm_TypeCColdBlock_Failure) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
const size_t kMmioRegCount = kMmioRangeSize / sizeof(uint32_t);
ddk_fake::FakeMmioRegRegion mmio_region(sizeof(uint32_t), kMmioRegCount);
fdf::MmioBuffer mmio_buffer = mmio_region.GetMmioBuffer();
mmio_region[kMailboxInterfaceOffset].SetWriteCallback(
[&](uint64_t value) { EXPECT_EQ(0x8000'0026, value) << "Unexpected command"; });
mmio_region[kMailboxInterfaceOffset].SetReadCallback([&]() -> uint64_t { return 0x0000'0026; });
mmio_region[kMailboxData0Offset].SetReadCallback([&]() -> uint64_t { return 0x0000'0001; });
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kUninitialized);
EXPECT_FALSE(ddi.AdvanceEnableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
}
TEST_F(TypeCDdiTigerLakeTest, EnableFsm_SafeModeSet_Success) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// DynamicFlexIoDisplayPortPhyModeStatus
// Type-C PHY is ready on DDI_TC_1.
{.address = 0x163890, .value = 0x0000'0001},
// DynamicFlexIoDisplayPortControllerSafeStateSettings
// Disable safe mode.
{.address = 0x163894, .value = 0x0000'0000},
{.address = 0x163894, .value = 0x0000'0001, .write = true},
{.address = 0x163894, .value = 0x0000'0001},
// DynamicFlexIoScratchPad
// Request Type-C live state.
{.address = 0x1638A0, .value = 0x0000'103f},
}));
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
EXPECT_TRUE(ddi.AdvanceEnableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kSafeModeSet);
}
TEST_F(TypeCDdiTigerLakeTest, EnableFsm_SafeModeSet_Failure) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// DynamicFlexIoDisplayPortPhyModeStatus
// Type-C PHY is not ready on DDI_TC_1.
{.address = 0x163890, .value = 0x0000'0002},
}));
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
EXPECT_FALSE(ddi.AdvanceEnableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kSafeModeSet);
}
TEST_F(TypeCDdiTigerLakeTest, EnableFsm_AuxPowerOn_Success) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// HipIndexReg0
{.address = 0x1010a0, .value = 0x0000'0000},
{.address = 0x1010a0, .value = 0x0000'0002, .write = true},
// DekelCommonConfigMicroControllerDword27
// PHY uC firmware is ready.
{.address = 0x16836C, .value = 0x0000'8000},
// DdiAuxControl
// Not using thunderbolt.
{.address = 0x64310, .value = 0x0000'0800},
{.address = 0x64310, .value = 0x0000'0000, .write = true},
}));
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kSafeModeSet);
EXPECT_TRUE(ddi.AdvanceEnableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kAuxPoweredOn);
}
TEST_F(TypeCDdiTigerLakeTest, EnableFsm_AuxPowerOn_Failure) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
class TestPowerCannotEnableAux : public TestPower {
public:
explicit TestPowerCannotEnableAux(fdf::MmioBuffer* mmio_space) : TestPower(mmio_space) {}
bool GetAuxIoPowerState(DdiId ddi_id) override { return false; }
};
TestPowerCannotEnableAux power_cannot_enable_aux(nullptr);
TypeCDdiTigerLake ddi(kTargetDdiId, &power_cannot_enable_aux, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kSafeModeSet);
EXPECT_FALSE(ddi.AdvanceEnableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kAuxPoweredOn);
}
TEST_F(TypeCDdiTigerLakeTest, EnableFsm_Initialized_AlwaysSuccess) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kAuxPoweredOn);
EXPECT_TRUE(ddi.AdvanceEnableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kInitialized);
}
TEST_F(TypeCDdiTigerLakeTest, EnableFsm_Initialized_IsTerminal) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kInitialized);
EXPECT_FALSE(ddi.AdvanceEnableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kInitialized);
}
TEST_F(TypeCDdiTigerLakeTest, DisableFsm_kInitialized_AlwaysSuccess) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kInitialized);
EXPECT_TRUE(ddi.AdvanceDisableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kAuxPoweredOn);
}
TEST_F(TypeCDdiTigerLakeTest, DisableFsm_AuxPoweredOn_AlwaysSuccess) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
{
class TestPowerCanDisableAux : public TestPower {
public:
explicit TestPowerCanDisableAux(fdf::MmioBuffer* mmio_space) : TestPower(mmio_space) {}
bool GetAuxIoPowerState(DdiId ddi_id) override { return false; }
};
TestPowerCanDisableAux power_can_disable_aux(nullptr);
TypeCDdiTigerLake ddi(kTargetDdiId, &power_can_disable_aux, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kAuxPoweredOn);
EXPECT_TRUE(ddi.AdvanceDisableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kSafeModeSet);
}
{
class TestPowerCannotDisableAux : public TestPower {
public:
explicit TestPowerCannotDisableAux(fdf::MmioBuffer* mmio_space) : TestPower(mmio_space) {}
bool GetAuxIoPowerState(DdiId ddi_id) override { return true; }
};
TestPowerCannotDisableAux power_cannot_disable_aux(nullptr);
TypeCDdiTigerLake ddi(kTargetDdiId, &power_cannot_disable_aux, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kAuxPoweredOn);
EXPECT_TRUE(ddi.AdvanceDisableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kSafeModeSet);
}
}
TEST_F(TypeCDdiTigerLakeTest, EnableFsm_SafeModeSet_AlwaysSuccess) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// DynamicFlexIoDisplayPortControllerSafeStateSettings
// Enable safe mode.
{.address = 0x163894, .value = 0x0000'0001},
{.address = 0x163894, .value = 0x0000'0000, .write = true},
{.address = 0x163894, .value = 0x0000'0000},
}));
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kSafeModeSet);
EXPECT_TRUE(ddi.AdvanceDisableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
}
TEST_F(TypeCDdiTigerLakeTest, DisableFsm_TypeCColdUnblock_Success) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kMailboxInterfaceOffset, .value = 0},
{.address = kMailboxData0Offset, .value = 0x0000'0001, .write = true},
{.address = kMailboxData1Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x8000'0026, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x0000'0026},
// The Type-C subsystem has re-entered TCCOLD.
{.address = kMailboxData0Offset, .value = 0x0000'0001},
{.address = kMailboxData1Offset, .value = 0x0000'0000},
}));
{
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
EXPECT_TRUE(ddi.AdvanceDisableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kUninitialized);
}
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kMailboxInterfaceOffset, .value = 0},
{.address = kMailboxData0Offset, .value = 0x0000'0001, .write = true},
{.address = kMailboxData1Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x8000'0026, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x0000'0026},
// The Type-C subsystem has not yet re-entered TCCOLD; other devices
// may still using the Type-C.
{.address = kMailboxData0Offset, .value = 0x0000'0000},
{.address = kMailboxData1Offset, .value = 0x0000'0000},
}));
{
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
EXPECT_TRUE(ddi.AdvanceDisableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kUninitialized);
}
}
TEST_F(TypeCDdiTigerLakeTest, DisableFsm_TypeCColdUnblock_Failure) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
const size_t kMmioRegCount = kMmioRangeSize / sizeof(uint32_t);
ddk_fake::FakeMmioRegRegion mmio_region(sizeof(uint32_t), kMmioRegCount);
fdf::MmioBuffer mmio_buffer = mmio_region.GetMmioBuffer();
mmio_region[kMailboxInterfaceOffset].SetWriteCallback(
[&](uint64_t value) { EXPECT_EQ(0x8000'0026, value) << "Unexpected command"; });
mmio_region[kMailboxInterfaceOffset].SetReadCallback([&]() -> uint64_t {
// Always busy.
return 0x8000'0026;
});
mmio_region[kMailboxData0Offset].SetReadCallback([&]() -> uint64_t { return 0x0000'0001; });
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
EXPECT_FALSE(ddi.AdvanceDisableFsm());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
}
TEST_F(TypeCDdiTigerLakeTest, Enable_Idempotency) {
TypeCDdiTigerLake ddi(DdiId::DDI_TC_1, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kInitialized);
EXPECT_TRUE(ddi.Enable());
EXPECT_TRUE(ddi.IsEnabled());
EXPECT_TRUE(ddi.Enable());
EXPECT_TRUE(ddi.IsEnabled());
}
TEST_F(TypeCDdiTigerLakeTest, Disable_Idempotency) {
TypeCDdiTigerLake ddi(DdiId::DDI_TC_1, &power_, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kUninitialized);
EXPECT_TRUE(ddi.Disable());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_TRUE(ddi.Disable());
EXPECT_FALSE(ddi.IsEnabled());
}
TEST_F(TypeCDdiTigerLakeTest, Enable_OnlyValidOnHealthy) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
const size_t kMmioRegCount = kMmioRangeSize / sizeof(uint32_t);
ddk_fake::FakeMmioRegRegion mmio_region(sizeof(uint32_t), kMmioRegCount);
fdf::MmioBuffer mmio_buffer = mmio_region.GetMmioBuffer();
EXPECT_DEATH(
{
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(
TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
ddi.Enable();
},
"IsHealthy");
EXPECT_DEATH(
{
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kSafeModeSet);
ddi.Enable();
},
"IsHealthy");
EXPECT_DEATH(
{
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kAuxPoweredOn);
ddi.Enable();
},
"IsHealthy");
EXPECT_NO_FATAL_FAILURE({
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kInitialized);
ddi.Enable();
});
EXPECT_NO_FATAL_FAILURE({
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kUninitialized);
ddi.Enable();
});
}
TEST_F(TypeCDdiTigerLakeTest, Disable_FailsOnUnhealthy) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_1;
const size_t kMmioRegCount = kMmioRangeSize / sizeof(uint32_t);
ddk_fake::FakeMmioRegRegion mmio_region(sizeof(uint32_t), kMmioRegCount);
fdf::MmioBuffer mmio_buffer = mmio_region.GetMmioBuffer();
{
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
EXPECT_FALSE(ddi.Disable());
}
{
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kSafeModeSet);
EXPECT_FALSE(ddi.Disable());
}
{
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kAuxPoweredOn);
EXPECT_FALSE(ddi.Disable());
}
}
TEST_F(TypeCDdiTigerLakeTest, Enable_Success) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_2;
// Unblock TCCOLD state.
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kMailboxInterfaceOffset, .value = 0},
{.address = kMailboxData0Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxData1Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x8000'0026, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x0000'0026},
// The Type-C subsystem has exited TCCOLD.
{.address = kMailboxData0Offset, .value = 0x0000'0000},
{.address = kMailboxData1Offset, .value = 0x0000'0000},
}));
// Set Type-C safe mode.
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// DynamicFlexIoDisplayPortPhyModeStatus
// Type-C PHY is ready on DDI_TC_2.
{.address = 0x163890, .value = 0x0000'0002},
// DynamicFlexIoDisplayPortControllerSafeStateSettings
// Disable safe mode.
{.address = 0x163894, .value = 0x0000'0000},
{.address = 0x163894, .value = 0x0000'0002, .write = true},
{.address = 0x163894, .value = 0x0000'0002},
// DynamicFlexIoScratchPad
// Request Type-C live state.
{.address = 0x1638A0, .value = 0x0000'3f10},
}));
// AUX power on
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// HipIndexReg0
{.address = 0x1010a0, .value = 0x0000'0001},
{.address = 0x1010a0, .value = 0x0000'0201, .write = true},
// DekelCommonConfigMicroControllerDword27
// PHY uC firmware is ready.
{.address = 0x16936C, .value = 0x0000'8000},
// DdiAuxControl
// Not using thunderbolt.
{.address = 0x64410, .value = 0x0000'0800},
{.address = 0x64410, .value = 0x0000'0000, .write = true},
}));
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_TRUE(ddi.Enable());
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_TRUE(ddi.IsEnabled());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kInitialized);
}
TEST_F(TypeCDdiTigerLakeTest, Enable_Failure_TcColdCannotBlock) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_2;
bool tccold_unblock_requested = false;
bool tccold_block_requested = false;
const size_t kMmioRegCount = kMmioRangeSize / sizeof(uint32_t);
ddk_fake::FakeMmioRegRegion mmio_region(sizeof(uint32_t), kMmioRegCount);
fdf::MmioBuffer mmio_buffer = mmio_region.GetMmioBuffer();
mmio_region[kMailboxInterfaceOffset].SetWriteCallback(
[&](uint64_t value) { EXPECT_EQ(0x8000'0026, value) << "Unexpected command"; });
mmio_region[kMailboxInterfaceOffset].SetReadCallback([&]() -> uint64_t { return 0x0000'0026; });
mmio_region[kMailboxData0Offset].SetWriteCallback([&](uint64_t data) {
if (data == 0x0000'0000) {
// The driver makes TCCOLD block request first.
EXPECT_FALSE(tccold_unblock_requested);
tccold_block_requested = true;
} else if (data == 0x0000'0001) {
// After TCCOLD block request fails, it tries to revert the command and
// unblocks TCCOLD.
EXPECT_TRUE(tccold_block_requested);
tccold_unblock_requested = true;
} else {
FAIL() << "Unexpected TCCOLD config";
}
});
mmio_region[kMailboxData0Offset].SetReadCallback([&]() -> uint64_t {
// TCCOLD block request never succeeds, the device is always in TCCOLD
// state.
return 0x0000'0001;
});
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_FALSE(ddi.Enable());
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_EQ(ddi.GetPhysicalLayerInfo().connection_type, DdiPhysicalLayer::ConnectionType::kNone);
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kUninitialized);
EXPECT_TRUE(tccold_block_requested);
EXPECT_TRUE(tccold_unblock_requested);
}
TEST_F(TypeCDdiTigerLakeTest, Enable_Failure_SafeModePhyNotAvailable) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_2;
// Unblock TCCOLD state.
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kMailboxInterfaceOffset, .value = 0},
{.address = kMailboxData0Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxData1Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x8000'0026, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x0000'0026},
// The Type-C subsystem has exited TCCOLD.
{.address = kMailboxData0Offset, .value = 0x0000'0000},
{.address = kMailboxData1Offset, .value = 0x0000'0000},
}));
// Set Type-C safe mode.
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// DynamicFlexIoDisplayPortPhyModeStatus
// Type-C PHY is not ready on DDI_TC_2.
{.address = 0x163890, .value = 0x0000'0000},
}));
// Revert "Set Type-C safe mode".
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// DynamicFlexIoDisplayPortControllerSafeStateSettings
// Enable safe mode.
{.address = 0x163894, .value = 0x0000'0002},
{.address = 0x163894, .value = 0x0000'0000, .write = true},
{.address = 0x163894, .value = 0x0000'0000},
}));
// Revert "Unblock TCCOLD state".
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kMailboxInterfaceOffset, .value = 0},
{.address = kMailboxData0Offset, .value = 0x0000'0001, .write = true},
{.address = kMailboxData1Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x8000'0026, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x0000'0026},
// The Type-C subsystem has re-entered TCCOLD.
{.address = kMailboxData0Offset, .value = 0x0000'0001},
{.address = kMailboxData1Offset, .value = 0x0000'0000},
}));
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer_,
/*is_static_port=*/false);
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_FALSE(ddi.Enable());
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_EQ(ddi.GetPhysicalLayerInfo().connection_type, DdiPhysicalLayer::ConnectionType::kNone);
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kUninitialized);
}
TEST_F(TypeCDdiTigerLakeTest, Enable_Failure_CannotEnableAux) {
static constexpr DdiId kTargetDdiId = DdiId::DDI_TC_2;
class TestPowerCannotEnableAux : public TestPower {
public:
explicit TestPowerCannotEnableAux(fdf::MmioBuffer* mmio_space) : TestPower(mmio_space) {}
void SetAuxIoPowerState(DdiId ddi_id, bool target_enabled) override {
EXPECT_EQ(ddi_id, kTargetDdiId);
(target_enabled ? enable_requested : disable_requested) = true;
}
bool GetAuxIoPowerState(DdiId ddi_id) override {
EXPECT_EQ(ddi_id, kTargetDdiId);
return false;
}
bool enable_requested = false;
bool disable_requested = false;
};
TestPowerCannotEnableAux power_cannot_enable_aux(nullptr);
// Unblock TCCOLD state.
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kMailboxInterfaceOffset, .value = 0},
{.address = kMailboxData0Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxData1Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x8000'0026, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x0000'0026},
// The Type-C subsystem has exited TCCOLD.
{.address = kMailboxData0Offset, .value = 0x0000'0000},
{.address = kMailboxData1Offset, .value = 0x0000'0000},
}));
// Set Type-C safe mode.
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// DynamicFlexIoDisplayPortPhyModeStatus
// Type-C PHY is ready on DDI_TC_2.
{.address = 0x163890, .value = 0x0000'0002},
// DynamicFlexIoDisplayPortControllerSafeStateSettings
// Disable safe mode.
{.address = 0x163894, .value = 0x0000'0000},
{.address = 0x163894, .value = 0x0000'0002, .write = true},
{.address = 0x163894, .value = 0x0000'0002},
// DynamicFlexIoScratchPad
// Request Type-C live state.
{.address = 0x1638A0, .value = 0x0000'3f10},
}));
// AUX power on fails; AUX IO is powered off through `Power`.
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList{});
// Revert "Set Type-C safe mode".
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// DynamicFlexIoDisplayPortControllerSafeStateSettings
// Enable safe mode.
{.address = 0x163894, .value = 0x0000'0002},
{.address = 0x163894, .value = 0x0000'0000, .write = true},
{.address = 0x163894, .value = 0x0000'0000},
}));
// Revert "Unblock TCCOLD state".
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kMailboxInterfaceOffset, .value = 0},
{.address = kMailboxData0Offset, .value = 0x0000'0001, .write = true},
{.address = kMailboxData1Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x8000'0026, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x0000'0026},
// The Type-C subsystem has re-entered TCCOLD.
{.address = kMailboxData0Offset, .value = 0x0000'0001},
{.address = kMailboxData1Offset, .value = 0x0000'0000},
}));
TypeCDdiTigerLake ddi(kTargetDdiId, &power_cannot_enable_aux, &mmio_buffer_,
/*is_static_port=*/false);
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_FALSE(ddi.Enable());
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_TRUE(power_cannot_enable_aux.enable_requested);
EXPECT_TRUE(power_cannot_enable_aux.disable_requested);
EXPECT_EQ(ddi.GetPhysicalLayerInfo().connection_type, DdiPhysicalLayer::ConnectionType::kNone);
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kUninitialized);
}
TEST_F(TypeCDdiTigerLakeTest, Enable_FailureOnBailout) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_2;
const size_t kMmioRegCount = kMmioRangeSize / sizeof(uint32_t);
ddk_fake::FakeMmioRegRegion mmio_region(sizeof(uint32_t), kMmioRegCount);
fdf::MmioBuffer mmio_buffer = mmio_region.GetMmioBuffer();
bool most_recent_tccold_request_is_block = false;
// TCCOLD command can be successfully handled only when it's a "Block" request
// (i.e. on "Enable()").
mmio_region[kMailboxInterfaceOffset].SetWriteCallback(
[&](uint64_t value) { EXPECT_EQ(0x8000'0026, value) << "Unexpected command"; });
mmio_region[kMailboxInterfaceOffset].SetReadCallback([&]() -> uint64_t {
return most_recent_tccold_request_is_block ? 0x0000'0026 : 0x8000'0026;
});
mmio_region[kMailboxData0Offset].SetWriteCallback(
[&](uint64_t data) { most_recent_tccold_request_is_block = (data == 0x0000'0000); });
mmio_region[kMailboxData0Offset].SetReadCallback([&]() -> uint64_t { return 0x0000'0000; });
// DynamicFlexIoDisplayPortPhyModeStatus: Type-C PHY is not ready on DDI_TC_2.
const size_t phy_mode_status_reg_addr =
registers::DynamicFlexIoDisplayPortPhyModeStatus::GetForDdi(kTargetDdiId).addr();
mmio_region[phy_mode_status_reg_addr].SetReadCallback([] { return 0x0000'0000; });
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_FALSE(ddi.Enable());
EXPECT_FALSE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
}
TEST_F(TypeCDdiTigerLakeTest, Disable_Success) {
static constexpr DdiId kTargetDdiId = DdiId::DDI_TC_2;
class TestPowerTrackingAux : public TestPower {
public:
explicit TestPowerTrackingAux(fdf::MmioBuffer* mmio_space) : TestPower(mmio_space) {}
void SetAuxIoPowerState(DdiId ddi_id, bool target_enabled) override {
EXPECT_EQ(ddi_id, kTargetDdiId);
EXPECT_FALSE(target_enabled);
disable_requested = true;
}
bool GetAuxIoPowerState(DdiId ddi_id) override {
EXPECT_EQ(ddi_id, kTargetDdiId);
return !disable_requested;
}
bool disable_requested = false;
};
TestPowerTrackingAux power(nullptr);
// AUX IO is powered off through `Power`.
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList{});
// Revert "Set Type-C safe mode".
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
// DynamicFlexIoDisplayPortControllerSafeStateSettings
// Enable safe mode.
{.address = 0x163894, .value = 0x0000'0002},
{.address = 0x163894, .value = 0x0000'0000, .write = true},
{.address = 0x163894, .value = 0x0000'0000},
}));
// Revert "Unblock TCCOLD state".
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kMailboxInterfaceOffset, .value = 0},
{.address = kMailboxData0Offset, .value = 0x0000'0001, .write = true},
{.address = kMailboxData1Offset, .value = 0x0000'0000, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x8000'0026, .write = true},
{.address = kMailboxInterfaceOffset, .value = 0x0000'0026},
// The Type-C subsystem has re-entered TCCOLD.
{.address = kMailboxData0Offset, .value = 0x0000'0001},
{.address = kMailboxData1Offset, .value = 0x0000'0000},
}));
TypeCDdiTigerLake ddi(kTargetDdiId, &power, &mmio_buffer_,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kInitialized);
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_TRUE(ddi.IsEnabled());
EXPECT_TRUE(ddi.Disable());
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_TRUE(power.disable_requested);
EXPECT_EQ(ddi.GetPhysicalLayerInfo().connection_type, DdiPhysicalLayer::ConnectionType::kNone);
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kUninitialized);
}
TEST_F(TypeCDdiTigerLakeTest, Disable_Failure_TcColdCannotUnblock) {
constexpr DdiId kTargetDdiId = DdiId::DDI_TC_2;
const size_t kMmioRegCount = kMmioRangeSize / sizeof(uint32_t);
ddk_fake::FakeMmioRegRegion mmio_region(sizeof(uint32_t), kMmioRegCount);
fdf::MmioBuffer mmio_buffer = mmio_region.GetMmioBuffer();
// Re-enable safe mode.
const size_t safe_state_reg_addr =
registers::DynamicFlexIoDisplayPortControllerSafeStateSettings::GetForDdi(kTargetDdiId)
.addr();
bool safe_mode_enabled = false;
mmio_region[safe_state_reg_addr].SetWriteCallback([&](uint64_t value) {
EXPECT_EQ(value, 0x0000'0000u);
safe_mode_enabled = true;
});
mmio_region[safe_state_reg_addr].SetReadCallback(
[&] { return safe_mode_enabled ? 0x0000'0000 : 0x0000'0002; });
// TCCOLD command fails on unblock.
mmio_region[kMailboxInterfaceOffset].SetWriteCallback(
[&](uint64_t value) { EXPECT_EQ(0x8000'0026u, value) << "Unexpected command"; });
mmio_region[kMailboxInterfaceOffset].SetReadCallback([&]() -> uint64_t { return 0x8000'0026; });
mmio_region[kMailboxData0Offset].SetWriteCallback(
[&](uint64_t value) { EXPECT_EQ(0x0000'0001u, value) << "Unexpected TCCOLD state"; });
mmio_region[kMailboxData0Offset].SetReadCallback([&]() -> uint64_t { return 0x0000'0001; });
TypeCDdiTigerLake ddi(kTargetDdiId, &power_, &mmio_buffer,
/*is_static_port=*/false);
ddi.SetInitializationPhaseForTesting(TypeCDdiTigerLake::InitializationPhase::kInitialized);
EXPECT_TRUE(ddi.IsHealthy());
EXPECT_TRUE(ddi.IsEnabled());
EXPECT_FALSE(ddi.Disable());
EXPECT_TRUE(safe_mode_enabled);
EXPECT_FALSE(ddi.IsHealthy());
EXPECT_FALSE(ddi.IsEnabled());
EXPECT_EQ(ddi.GetInitializationPhaseForTesting(),
TypeCDdiTigerLake::InitializationPhase::kTypeCColdBlocked);
}
TEST_F(TypeCDdiTigerLakeTest, ReadPhysicalLayerInfo_StaticPort) {
for (const DdiId ddi_id : {
DdiId::DDI_TC_1,
DdiId::DDI_TC_2,
DdiId::DDI_TC_3,
DdiId::DDI_TC_4,
DdiId::DDI_TC_5,
DdiId::DDI_TC_6,
}) {
auto scratch_pad = registers::DynamicFlexIoScratchPad::GetForDdi(ddi_id).FromValue(0);
scratch_pad.set_is_modular_flexi_io_adapter(true).set_firmware_supports_mfd(true);
if ((ddi_id - DdiId::DDI_TC_1) % 2 == 0) {
scratch_pad.set_type_c_live_state_connector_0(static_cast<uint32_t>(
registers::DynamicFlexIoScratchPad::TypeCLiveState::kNoHotplugDisplay));
} else {
scratch_pad.set_type_c_live_state_connector_1(static_cast<uint32_t>(
registers::DynamicFlexIoScratchPad::TypeCLiveState::kNoHotplugDisplay));
}
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = scratch_pad.reg_addr(), .value = scratch_pad.reg_value()},
}));
const TypeCDdiTigerLake ddi(ddi_id, &power_, &mmio_buffer_,
/*is_static_port=*/true);
const auto physical_layer_info = ddi.ReadPhysicalLayerInfo();
EXPECT_EQ(physical_layer_info.ddi_type, TypeCDdiTigerLake::DdiType::kTypeC);
EXPECT_EQ(physical_layer_info.connection_type, TypeCDdiTigerLake::ConnectionType::kBuiltIn);
EXPECT_EQ(physical_layer_info.max_allowed_dp_lane_count, 4u);
}
}
TEST_F(TypeCDdiTigerLakeTest, ReadPhysicalLayerInfo_NoTypeC) {
for (const DdiId ddi_id : {
DdiId::DDI_TC_1,
DdiId::DDI_TC_2,
DdiId::DDI_TC_3,
DdiId::DDI_TC_4,
DdiId::DDI_TC_5,
DdiId::DDI_TC_6,
}) {
auto scratch_pad = registers::DynamicFlexIoScratchPad::GetForDdi(ddi_id).FromValue(0);
scratch_pad.set_is_modular_flexi_io_adapter(true).set_firmware_supports_mfd(true);
if ((ddi_id - DdiId::DDI_TC_1) % 2 == 0) {
scratch_pad.set_type_c_live_state_connector_0(static_cast<uint32_t>(
registers::DynamicFlexIoScratchPad::TypeCLiveState::kNoHotplugDisplay));
} else {
scratch_pad.set_type_c_live_state_connector_1(static_cast<uint32_t>(
registers::DynamicFlexIoScratchPad::TypeCLiveState::kNoHotplugDisplay));
}
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = scratch_pad.reg_addr(), .value = scratch_pad.reg_value()},
}));
const TypeCDdiTigerLake ddi(ddi_id, &power_, &mmio_buffer_,
/*is_static_port=*/false);
const auto physical_layer_info = ddi.ReadPhysicalLayerInfo();
EXPECT_EQ(physical_layer_info.ddi_type, TypeCDdiTigerLake::DdiType::kTypeC);
EXPECT_EQ(physical_layer_info.connection_type, TypeCDdiTigerLake::ConnectionType::kNone);
EXPECT_EQ(physical_layer_info.max_allowed_dp_lane_count, 0u);
}
}
TEST_F(TypeCDdiTigerLakeTest, ReadPhysicalLayerInfo_TypeCDisplayPortAlt) {
for (const DdiId ddi_id : {
DdiId::DDI_TC_1,
DdiId::DDI_TC_2,
DdiId::DDI_TC_3,
DdiId::DDI_TC_4,
DdiId::DDI_TC_5,
DdiId::DDI_TC_6,
}) {
auto scratch_pad = registers::DynamicFlexIoScratchPad::GetForDdi(ddi_id).FromValue(0);
scratch_pad.set_is_modular_flexi_io_adapter(true).set_firmware_supports_mfd(true);
if ((ddi_id - DdiId::DDI_TC_1) % 2 == 0) {
scratch_pad.set_type_c_live_state_connector_0(static_cast<uint32_t>(
registers::DynamicFlexIoScratchPad::TypeCLiveState::kTypeCHotplugDisplay));
scratch_pad.set_display_port_tx_lane_assignment_bits_connector_0(0b0011);
} else {
scratch_pad.set_type_c_live_state_connector_1(static_cast<uint32_t>(
registers::DynamicFlexIoScratchPad::TypeCLiveState::kTypeCHotplugDisplay));
scratch_pad.set_display_port_tx_lane_assignment_bits_connector_1(0b0011);
}
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = scratch_pad.reg_addr(), .value = scratch_pad.reg_value()},
}));
const TypeCDdiTigerLake ddi(ddi_id, &power_, &mmio_buffer_,
/*is_static_port=*/false);
const auto physical_layer_info = ddi.ReadPhysicalLayerInfo();
EXPECT_EQ(physical_layer_info.ddi_type, TypeCDdiTigerLake::DdiType::kTypeC);
EXPECT_EQ(physical_layer_info.connection_type,
TypeCDdiTigerLake::ConnectionType::kTypeCDisplayPortAltMode);
EXPECT_EQ(physical_layer_info.max_allowed_dp_lane_count, 2u);
}
}
TEST_F(TypeCDdiTigerLakeTest, ReadPhysicalLayerInfo_Thunderbolt) {
for (const DdiId ddi_id : {
DdiId::DDI_TC_1,
DdiId::DDI_TC_2,
DdiId::DDI_TC_3,
DdiId::DDI_TC_4,
DdiId::DDI_TC_5,
DdiId::DDI_TC_6,
}) {
auto scratch_pad = registers::DynamicFlexIoScratchPad::GetForDdi(ddi_id).FromValue(0);
scratch_pad.set_is_modular_flexi_io_adapter(true).set_firmware_supports_mfd(true);
if ((ddi_id - DdiId::DDI_TC_1) % 2 == 0) {
scratch_pad.set_type_c_live_state_connector_0(static_cast<uint32_t>(
registers::DynamicFlexIoScratchPad::TypeCLiveState::kThunderboltHotplugDisplay));
} else {
scratch_pad.set_type_c_live_state_connector_1(static_cast<uint32_t>(
registers::DynamicFlexIoScratchPad::TypeCLiveState::kThunderboltHotplugDisplay));
}
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = scratch_pad.reg_addr(), .value = scratch_pad.reg_value()},
}));
const TypeCDdiTigerLake ddi(ddi_id, &power_, &mmio_buffer_,
/*is_static_port=*/false);
const auto physical_layer_info = ddi.ReadPhysicalLayerInfo();
EXPECT_EQ(physical_layer_info.ddi_type, TypeCDdiTigerLake::DdiType::kTypeC);
EXPECT_EQ(physical_layer_info.connection_type,
TypeCDdiTigerLake::ConnectionType::kTypeCThunderbolt);
EXPECT_EQ(physical_layer_info.max_allowed_dp_lane_count, 4u);
}
}
class ComboDdiTigerLakeTest : public ::testing::Test {
public:
ComboDdiTigerLakeTest() = default;
~ComboDdiTigerLakeTest() override = default;
void SetUp() override {}
void TearDown() override { mmio_range_.CheckAllAccessesReplayed(); }
protected:
constexpr static int kMmioRangeSize = 0x200000;
ddk_mock::MockMmioRange mmio_range_{kMmioRangeSize, ddk_mock::MockMmioRange::Size::k32};
fdf::MmioBuffer mmio_buffer_{mmio_range_.GetMmioBuffer()};
};
constexpr int kPhyMiscAOffset = 0x64c00;
constexpr int kPhyMiscBOffset = 0x64c04;
constexpr int kPortClDw5BOffset = 0x6c014;
constexpr int kPortCompDw0BOffset = 0x6c100;
constexpr int kPortCompDw1BOffset = 0x6c104;
constexpr int kPortCompDw3BOffset = 0x6c10c;
constexpr int kPortCompDw8BOffset = 0x6c120;
constexpr int kPortCompDw9BOffset = 0x6c124;
constexpr int kPortCompDw10BOffset = 0x6c128;
constexpr int kPortPcsDw1AuxBOffset = 0x6c304;
constexpr int kPortTxDw8AuxBOffset = 0x6c3a0;
constexpr int kPortPcsDw1Ln0BOffset = 0x6c804;
constexpr int kPortTxDw8Ln0BOffset = 0x6c8a0;
constexpr int kPortPcsDw1Ln1BOffset = 0x6c904;
constexpr int kPortTxDw8Ln1BOffset = 0x6c9a0;
constexpr int kPortPcsDw1Ln2BOffset = 0x6ca04;
constexpr int kPortTxDw8Ln2BOffset = 0x6caa0;
constexpr int kPortPcsDw1Ln3BOffset = 0x6cb04;
constexpr int kPortTxDw8Ln3BOffset = 0x6cba0;
constexpr int kPortClDw5AOffset = 0x162014;
constexpr int kPortCompDw0AOffset = 0x162100;
constexpr int kPortCompDw1AOffset = 0x162104;
constexpr int kPortCompDw3AOffset = 0x16210c;
constexpr int kPortCompDw8AOffset = 0x162120;
constexpr int kPortCompDw9AOffset = 0x162124;
constexpr int kPortCompDw10AOffset = 0x162128;
constexpr int kPortPcsDw1AuxAOffset = 0x162304;
constexpr int kPortTxDw8AuxAOffset = 0x1623a0;
constexpr int kPortPcsDw1Ln0AOffset = 0x162804;
constexpr int kPortTxDw8Ln0AOffset = 0x1628a0;
constexpr int kPortPcsDw1Ln1AOffset = 0x162904;
constexpr int kPortTxDw8Ln1AOffset = 0x1629a0;
constexpr int kPortPcsDw1Ln2AOffset = 0x162a04;
constexpr int kPortTxDw8Ln2AOffset = 0x162aa0;
constexpr int kPortPcsDw1Ln3AOffset = 0x162b04;
constexpr int kPortTxDw8Ln3AOffset = 0x162ba0;
TEST_F(ComboDdiTigerLakeTest, InitializeDdiADell5420) {
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kPortCompDw3AOffset, .value = 0xc0606b25},
{.address = kPortCompDw1AOffset, .value = 0x81000400},
{.address = kPortCompDw9AOffset, .value = 0x62ab67bb},
{.address = kPortCompDw10AOffset, .value = 0x51914f96},
{.address = kPortClDw5AOffset, .value = 0x1204047b},
{.address = kPortTxDw8AuxAOffset, .value = 0x30037c9c},
{.address = kPortPcsDw1AuxAOffset, .value = 0x1c300004},
{.address = kPortTxDw8Ln0AOffset, .value = 0x300335dc},
{.address = kPortPcsDw1Ln0AOffset, .value = 0x1c300004},
{.address = kPortTxDw8Ln1AOffset, .value = 0x3003379c},
{.address = kPortPcsDw1Ln1AOffset, .value = 0x1c300004},
{.address = kPortTxDw8Ln2AOffset, .value = 0x3003501c},
{.address = kPortPcsDw1Ln2AOffset, .value = 0x1c300004},
{.address = kPortTxDw8Ln3AOffset, .value = 0x3003501c},
{.address = kPortPcsDw1Ln3AOffset, .value = 0x1c300004},
{.address = kPhyMiscAOffset, .value = 0x23000000},
{.address = kPortCompDw8AOffset, .value = 0x010d0280},
{.address = kPortCompDw0AOffset, .value = 0x80005f25},
}));
ComboDdiTigerLake ddi(DdiId::DDI_A, &mmio_buffer_);
EXPECT_EQ(true, ddi.Initialize());
}
TEST_F(ComboDdiTigerLakeTest, InitializeDdiBDell5420) {
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kPortCompDw3BOffset, .value = 0xc0606b25},
{.address = kPortCompDw1BOffset, .value = 0x81000400},
{.address = kPortCompDw9BOffset, .value = 0x62ab67bb},
{.address = kPortCompDw10BOffset, .value = 0x51914f96},
{.address = kPortClDw5BOffset, .value = 0x12040478},
{.address = kPortTxDw8AuxBOffset, .value = 0x3003501c},
{.address = kPortPcsDw1AuxBOffset, .value = 0x1c300004},
{.address = kPortTxDw8Ln0BOffset, .value = 0x3003501c},
{.address = kPortPcsDw1Ln0BOffset, .value = 0x1c300004},
{.address = kPortTxDw8Ln1BOffset, .value = 0x3003501c},
{.address = kPortPcsDw1Ln1BOffset, .value = 0x1c300004},
{.address = kPortTxDw8Ln2BOffset, .value = 0x3003501c},
{.address = kPortPcsDw1Ln2BOffset, .value = 0x1c300004},
{.address = kPortTxDw8Ln3BOffset, .value = 0x3003501c},
{.address = kPortPcsDw1Ln3BOffset, .value = 0x1c300004},
{.address = kPhyMiscBOffset, .value = 0x23000000},
{.address = kPortCompDw8BOffset, .value = 0x000d0280},
{.address = kPortCompDw0BOffset, .value = 0x80005f26},
}));
ComboDdiTigerLake ddi(DdiId::DDI_B, &mmio_buffer_);
EXPECT_EQ(true, ddi.Initialize());
}
TEST_F(ComboDdiTigerLakeTest, InitializeDdiBNuc11) {
mmio_range_.Expect(ddk_mock::MockMmioRange::AccessList({
{.address = kPortCompDw3BOffset, .value = 0xc0608025},
{.address = kPortCompDw1BOffset, .value = 0x81000400},
{.address = kPortCompDw9BOffset, .value = 0x62ab67bb},
{.address = kPortCompDw10BOffset, .value = 0x51914f96},
{.address = kPortClDw5BOffset, .value = 0x1204047b},
{.address = kPortTxDw8AuxBOffset, .value = 0x3003501c},
{.address = kPortPcsDw1AuxBOffset, .value = 0x18300004},
{.address = kPortTxDw8Ln0BOffset, .value = 0x300355fc},
{.address = kPortPcsDw1Ln0BOffset, .value = 0x18300004},
{.address = kPortTxDw8Ln1BOffset, .value = 0x300335fc},
{.address = kPortPcsDw1Ln1BOffset, .value = 0x18300004},
{.address = kPortTxDw8Ln2BOffset, .value = 0x300335bc},
{.address = kPortPcsDw1Ln2BOffset, .value = 0x18300004},
{.address = kPortTxDw8Ln3BOffset, .value = 0x300335dc},
{.address = kPortPcsDw1Ln3BOffset, .value = 0x18300004},
{.address = kPhyMiscBOffset, .value = 0x23000000},
{.address = kPortCompDw8BOffset, .value = 0x000d0280},
{.address = kPortCompDw0BOffset, .value = 0x80005f28},
}));
ComboDdiTigerLake ddi(DdiId::DDI_B, &mmio_buffer_);
EXPECT_EQ(true, ddi.Initialize());
}
} // namespace
} // namespace i915