blob: 0e30fcbeb73519d8f619ae58530e09898d5cf7f1 [file] [log] [blame]
// Copyright 2017 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 <lib/zx/vmo.h>
#include "display-device.h"
#include "intel-i915.h"
#include "macros.h"
#include "registers.h"
#include "registers-dpll.h"
#include "registers-transcoder.h"
namespace i915 {
DisplayDevice::DisplayDevice(Controller* controller, uint64_t id,
registers::Ddi ddi, registers::Trans trans, registers::Pipe pipe)
: controller_(controller), id_(id), ddi_(ddi), trans_(trans), pipe_(pipe) {}
DisplayDevice::~DisplayDevice() {
if (inited_) {
ResetPipe();
ResetTrans();
ResetDdi();
}
}
hwreg::RegisterIo* DisplayDevice::mmio_space() const {
return controller_->mmio_space();
}
void DisplayDevice::ResetPipe() {
controller_->ResetPipe(pipe_);
}
bool DisplayDevice::ResetTrans() {
return controller_->ResetTrans(trans_);
}
bool DisplayDevice::ResetDdi() {
return controller_->ResetDdi(ddi_);
}
bool DisplayDevice::Init() {
ddi_power_ = controller_->power()->GetDdiPowerWellRef(ddi_);
pipe_power_ = controller_->power()->GetPipePowerWellRef(pipe_);
if (!QueryDevice(&edid_)) {
return false;
}
edid::timing_params_t preferred_timing;
if (!edid_.GetPreferredTiming(&preferred_timing)) {
return false;
}
info_.pixel_clock_10khz = preferred_timing.pixel_freq_10khz;
info_.h_addressable = preferred_timing.horizontal_addressable;
info_.h_front_porch = preferred_timing.horizontal_front_porch;
info_.h_sync_pulse = preferred_timing.horizontal_sync_pulse;
info_.h_blanking = preferred_timing.horizontal_blanking;
info_.v_addressable = preferred_timing.vertical_addressable;
info_.v_front_porch = preferred_timing.vertical_front_porch;
info_.v_sync_pulse = preferred_timing.vertical_sync_pulse;
info_.v_blanking = preferred_timing.vertical_blanking;
info_.mode_flags = (preferred_timing.vertical_sync_pulse ? MODE_FLAG_VSYNC_POSITIVE : 0)
| (preferred_timing.horizontal_sync_pulse ? MODE_FLAG_HSYNC_POSITIVE : 0)
| (preferred_timing.interlaced ? MODE_FLAG_INTERLACED : 0);
ResetPipe();
if (!ResetTrans() || !ResetDdi()) {
return false;
}
if (!DoModeset()) {
return false;
}
inited_ = true;
return true;
}
bool DisplayDevice::Resume() {
if (!DoModeset()) {
return false;
}
if (is_enabled_) {
controller_->interrupts()->EnablePipeVsync(pipe_, true);
}
return true;
}
void DisplayDevice::ApplyConfiguration(display_config_t* config) {
bool enabled = config != nullptr;
if (enabled != is_enabled_) {
controller_->interrupts()->EnablePipeVsync(pipe_, enabled);
is_enabled_ = enabled;
}
if (!is_enabled_) {
return;
}
registers::PipeRegs pipe_regs(pipe());
image_type_ = config->image.type;
auto stride_reg = pipe_regs.PlaneSurfaceStride().FromValue(0);
stride_reg.set_stride(config->image.type, config->image.width, config->image.pixel_format);
stride_reg.WriteTo(controller_->mmio_space());
auto plane_ctrl = pipe_regs.PlaneControl().ReadFrom(controller_->mmio_space());
if (config->image.type == IMAGE_TYPE_SIMPLE) {
plane_ctrl.set_tiled_surface(plane_ctrl.kLinear);
} else if (config->image.type == IMAGE_TYPE_X_TILED) {
plane_ctrl.set_tiled_surface(plane_ctrl.kTilingX);
} else if (config->image.type == IMAGE_TYPE_Y_LEGACY_TILED) {
plane_ctrl.set_tiled_surface(plane_ctrl.kTilingYLegacy);
} else {
ZX_ASSERT(config->image.type == IMAGE_TYPE_YF_TILED);
plane_ctrl.set_tiled_surface(plane_ctrl.kTilingYF);
}
plane_ctrl.WriteTo(controller_->mmio_space());
uint32_t base_address = static_cast<uint32_t>(reinterpret_cast<uint64_t>(config->image.handle));
auto plane_surface = pipe_regs.PlaneSurface().ReadFrom(controller_->mmio_space());
plane_surface.set_surface_base_addr(base_address >> plane_surface.kRShiftCount);
plane_surface.WriteTo(controller_->mmio_space());
}
} // namespace i915