blob: ab8a35b8d616353ffb75942495752c2a9b5f1ece [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/fuse-config.h"
#include <lib/ddk/debug.h>
#include <lib/mmio/mmio.h>
#include <zircon/assert.h>
#include "src/graphics/display/drivers/intel-i915/pci-ids.h"
#include "src/graphics/display/drivers/intel-i915/registers.h"
namespace i915 {
namespace {
FuseConfig ReadFuseConfigTigerLake(fdf::MmioBuffer& mmio_space) {
auto dfsm_register = registers::DisplayFuses::Get().ReadFrom(&mmio_space);
return FuseConfig{
.core_clock_limit_khz = 652'800, // No CDCLK limit fuses.
.graphics_enabled = true, // No global disable fuse.
.pipe_enabled =
{
!dfsm_register.pipe_a_disabled(),
!dfsm_register.pipe_b_disabled(),
!dfsm_register.pipe_c_disabled(),
!dfsm_register.pipe_d_disabled(),
},
.edp_enabled = !dfsm_register.edp_disabled(),
.display_capture_enabled = !dfsm_register.display_capture_disabled(),
.display_stream_compression_enabled = !dfsm_register.display_stream_compression_disabled(),
.frame_buffer_compression_enabled = !dfsm_register.power_management_disabled(),
.display_power_savings_enabled = !dfsm_register.power_management_disabled(),
};
}
int CoreClockLimitKhzSkylake(registers::DisplayFuses::CoreClockLimit clock_limit) {
static_assert(registers::DisplayFuses::CoreClockLimit::k675Mhz <
registers::DisplayFuses::CoreClockLimit::k337_5Mhz);
ZX_DEBUG_ASSERT_MSG(clock_limit >= registers::DisplayFuses::CoreClockLimit::k675Mhz,
"clock_limit should be a 2-bit field, but is %d",
static_cast<int>(clock_limit));
ZX_DEBUG_ASSERT_MSG(clock_limit <= registers::DisplayFuses::CoreClockLimit::k337_5Mhz,
"clock_limit should be a 2-bit field, but is %d",
static_cast<int>(clock_limit));
switch (clock_limit) {
case registers::DisplayFuses::CoreClockLimit::k675Mhz:
return 675'000;
case registers::DisplayFuses::CoreClockLimit::k540Mhz:
return 540'000;
case registers::DisplayFuses::CoreClockLimit::k450Mhz:
return 450'000;
case registers::DisplayFuses::CoreClockLimit::k337_5Mhz:
return 337'500;
};
// We should never get here, per the asserts above. If we do... returning the
// most conservative limit minimizes the harm that may come from feeding this
// result into clocking decisions.
return 337'500;
}
FuseConfig ReadFuseConfigSkylake(fdf::MmioBuffer& mmio_space) {
auto dfsm_register = registers::DisplayFuses::Get().ReadFrom(&mmio_space);
return FuseConfig{
.core_clock_limit_khz = CoreClockLimitKhzSkylake(dfsm_register.GetCoreClockLimit()),
.graphics_enabled = !dfsm_register.graphics_disabled(),
.pipe_enabled =
{
!dfsm_register.pipe_a_disabled(), !dfsm_register.pipe_b_disabled(),
!dfsm_register.pipe_c_disabled(),
false, // No pipe D on these models.
},
.edp_enabled = !dfsm_register.edp_disabled(),
.display_capture_enabled = !dfsm_register.display_capture_disabled(),
.display_stream_compression_enabled = true, // No DSC fuse.
.frame_buffer_compression_enabled = !dfsm_register.power_management_disabled(),
.display_power_savings_enabled = !dfsm_register.power_management_disabled(),
};
}
} // namespace
FuseConfig FuseConfig::ReadFrom(fdf::MmioBuffer& mmio_space, uint16_t device_id) {
if (is_tgl(device_id))
return ReadFuseConfigTigerLake(mmio_space);
if (is_skl(device_id) || is_kbl(device_id))
return ReadFuseConfigSkylake(mmio_space);
if (is_test_device(device_id))
return FuseConfig{};
ZX_DEBUG_ASSERT_MSG(false, "Unsupported PCI device ID: %x", device_id);
}
void FuseConfig::Log() {
if (!graphics_enabled)
zxlogf(WARNING, "Unusual fuse state - Graphics disabled");
for (size_t i = 0; i < std::size(pipe_enabled); ++i) {
if (!pipe_enabled[i])
zxlogf(WARNING, "Unusual fuse state - Pipe %zu disabled", i);
}
if (!edp_enabled)
zxlogf(WARNING, "Unusual fuse state - eDP disabled");
if (!display_capture_enabled)
zxlogf(WARNING, "Unusual fuse state - WD (display capture) disabled");
if (!display_stream_compression_enabled)
zxlogf(WARNING, "Unusual fuse state - DSC disabled");
if (!frame_buffer_compression_enabled)
zxlogf(WARNING, "Unusual fuse state - FBC disabled");
if (!display_power_savings_enabled)
zxlogf(WARNING, "Unusual fuse state - DPST disabled");
zxlogf(TRACE, "Maximum clock: %d kHz", core_clock_limit_khz);
}
} // namespace i915