blob: d7dc4803276aaa954a6e9b03866cf713b60ab817 [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/pipe-manager.h"
#include <lib/mmio-ptr/fake.h>
#include <lib/mmio/mmio.h>
#include <memory>
#include <vector>
#include <fake-mmio-reg/fake-mmio-reg.h>
#include <gtest/gtest.h>
#include "src/graphics/display/drivers/intel-i915/ddi-physical-layer-manager.h"
#include "src/graphics/display/drivers/intel-i915/dpll.h"
#include "src/graphics/display/drivers/intel-i915/intel-i915.h"
#include "src/graphics/display/drivers/intel-i915/pci-ids.h"
#include "src/graphics/display/drivers/intel-i915/pipe.h"
#include "src/graphics/display/drivers/intel-i915/registers-ddi.h"
#include "src/graphics/display/drivers/intel-i915/registers-pipe.h"
#include "src/graphics/display/lib/api-types-cpp/display-id.h"
#include "src/graphics/display/lib/api-types-cpp/display-timing.h"
namespace i915 {
class PipeManagerTest : public ::testing::Test {
public:
PipeManagerTest() : controller_(nullptr) {}
void SetUp() override {
mmio_buffer_.emplace(reg_region_.GetMmioBuffer());
controller_.SetMmioForTesting(mmio_buffer_->View(0));
controller_.SetPowerWellForTesting(Power::New(controller_.mmio_space(), kTestDeviceDid));
}
void TearDown() override {
// Unset so controller teardown doesn't crash.
controller_.ResetMmioSpaceForTesting();
}
Controller* controller() { return &controller_; }
protected:
constexpr static uint32_t kMinimumRegCount = 0xd0000 / sizeof(uint32_t);
ddk_fake::FakeMmioRegRegion reg_region_{sizeof(uint32_t), kMinimumRegCount};
std::optional<fdf::MmioBuffer> mmio_buffer_;
Controller controller_;
};
class FakeDisplay : public DisplayDevice {
public:
FakeDisplay(Controller* controller, display::DisplayId id, DdiId ddi_id, Type type)
: DisplayDevice(controller, id, ddi_id, DdiReference(), type) {}
~FakeDisplay() override = default;
// DisplayDevice overrides:
bool Query() final { return true; }
bool InitWithDdiPllConfig(const DdiPllConfig& pll_config) final { return true; }
private:
// DisplayDevice overrides:
bool InitDdi() final { return true; }
bool DdiModeset(const display::DisplayTiming& mode) final { return true; }
bool PipeConfigPreamble(const display::DisplayTiming& mode, PipeId pipe_id,
TranscoderId transcoder_id) final {
return true;
}
bool PipeConfigEpilogue(const display::DisplayTiming& mode, PipeId pipe_id,
TranscoderId transcoder_id) final {
return true;
}
DdiPllConfig ComputeDdiPllConfig(int32_t pixel_clock_khz) final { return {}; }
int32_t LoadPixelRateForTranscoderKhz(TranscoderId transcoder_id) final { return 0; }
ddk::I2cImplProtocolClient i2c() final { return {}; }
bool CheckPixelRate(int64_t pixel_rate_hz) final { return true; }
};
// This tests if the PipeManager can allocate pipe for display devices and
// bind the display correctly.
TEST_F(PipeManagerTest, SkylakeAllocatePipe) {
controller_.SetPipeManagerForTesting(std::make_unique<PipeManagerSkylake>(controller()));
PipeManager* pm = controller_.pipe_manager();
// Allocate pipe for DP display.
display::DisplayId kDisplay1Id(1);
std::unique_ptr<DisplayDevice> display1 = std::make_unique<FakeDisplay>(
controller(), kDisplay1Id, DdiId::DDI_B, DisplayDevice::Type::kDp);
Pipe* pipe1 = pm->RequestPipe(*display1);
display1->set_pipe(pipe1);
EXPECT_TRUE(pipe1);
EXPECT_TRUE(pipe1->in_use());
EXPECT_EQ(pipe1->attached_display_id(), kDisplay1Id);
EXPECT_EQ(pipe1->tied_transcoder_id(), pipe1->connected_transcoder_id());
// Allocate pipe for eDP display.
controller()->igd_opregion_for_testing()->SetIsEdpForTesting(DdiId::DDI_A, true);
display::DisplayId kDisplay2Id(2);
std::unique_ptr<DisplayDevice> display2 = std::make_unique<FakeDisplay>(
controller(), kDisplay2Id, DdiId::DDI_A, DisplayDevice::Type::kEdp);
Pipe* pipe2 = pm->RequestPipe(*display2);
display2->set_pipe(pipe2);
EXPECT_TRUE(pipe2);
EXPECT_NE(pipe2, pipe1);
EXPECT_TRUE(pipe2->in_use());
EXPECT_EQ(pipe2->attached_display_id(), kDisplay2Id);
EXPECT_EQ(pipe2->connected_transcoder_id(), TranscoderId::TRANSCODER_EDP);
display1.reset();
EXPECT_FALSE(pipe1->in_use());
display2.reset();
EXPECT_FALSE(pipe2->in_use());
}
// This tests if the driver can reclaim used pipe and transcoder when the
// display is removed so that the pipes can be used for future devices.
TEST_F(PipeManagerTest, SkylakeReclaimUsedPipe) {
controller_.SetPipeManagerForTesting(std::make_unique<PipeManagerSkylake>(controller()));
PipeManager* pm = controller_.pipe_manager();
for (size_t display_id_value = 1u;
display_id_value <= PipeIds<registers::Platform::kKabyLake>().size() * 10;
display_id_value++) {
const display::DisplayId display_id{display_id_value};
std::unique_ptr<DisplayDevice> display = std::make_unique<FakeDisplay>(
controller(), display_id, DdiId::DDI_B, DisplayDevice::Type::kDp);
Pipe* pipe = pm->RequestPipe(*display);
display->set_pipe(pipe);
EXPECT_TRUE(pipe);
// On the end of each for loop, |display| is destroyed and |pipe| will be
// reclaimed by PipeManager.
}
}
} // namespace i915