blob: 5a752a8a2839817c0539ac9f68581eadc5754fe4 [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 <fuchsia/hardware/display/controller/c/banjo.h>
#include <lib/fit/function.h>
#include <lib/mmio/mmio-buffer.h>
#include <lib/mmio/mmio.h>
#include <lib/sysmem-version/sysmem-version.h>
#include <lib/zx/vmo.h>
#include <cstdint>
#include <list>
#include <unordered_map>
#include <ddktl/device.h>
#include <region-alloc/region-alloc.h>
#include "src/graphics/display/drivers/intel-i915/gtt.h"
#include "src/graphics/display/drivers/intel-i915/hardware-common.h"
#include "src/graphics/display/drivers/intel-i915/power.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/drivers/intel-i915/registers-transcoder.h"
#include "src/graphics/display/lib/api-types-cpp/config-stamp.h"
#include "src/graphics/display/lib/api-types-cpp/display-id.h"
namespace i915 {
class Controller;
class DisplayDevice;
class Pipe {
Pipe(fdf::MmioBuffer* mmio_space, registers::Platform platform, PipeId pipe_id,
PowerWellRef pipe_power);
virtual ~Pipe() = default;
Pipe(const Pipe&) = delete;
Pipe(Pipe&&) = delete;
Pipe& operator=(const Pipe&) = delete;
Pipe& operator=(Pipe&&) = delete;
void AttachToDisplay(display::DisplayId display_id, bool is_edp);
void Detach();
void ApplyModeConfig(const display_mode_t& mode);
using GetImagePixelFormatFunc = fit::function<PixelFormatAndModifier(const image_t* image)>;
using SetupGttImageFunc =
fit::function<const GttRegion&(const image_t* image, uint32_t rotation)>;
void ApplyConfiguration(const display_config_t* banjo_display_config,
display::ConfigStamp config_stamp,
const SetupGttImageFunc& setup_gtt_image,
const GetImagePixelFormatFunc& get_pixel_format);
// Reset pipe registers and transcoders.
void Reset();
// Reset the pipe planes (layers).
void ResetPlanes();
// Resets the transcoder identified by `transcoder_id`.
static void ResetTranscoder(TranscoderId transcoder_id, registers::Platform platform,
fdf::MmioBuffer* mmio_space);
void LoadActiveMode(display_mode_t* mode);
PipeId pipe_id() const { return pipe_id_; }
// Identifies the transcoder that is always tied to the pipe.
// Each pipe has a transcoder tied to it, which can output most display
// protocols (DisplayPort, HDMI, DVI). This method identifies the pipe's tied
// transcoder. The return value never changes, for a given pipe.
// See `connected_transcoder_id()` for identifying the transcoder that the
// pipe is currently using.
TranscoderId tied_transcoder_id() const { return static_cast<TranscoderId>(pipe_id_); }
// Identifies the transcoder that is currently receiving the pipe's output.
// Each pipe has a tied transcoder, which can output most display protocols.
// The display engine also has some specialized transcoders, which can be
// connected to any pipe. The specialized transcoders are tied to DDIs that
// use specialized protocols (Embedded DisplayPort, DDI), and used for writing
// back to memory ("WD / Wireless Display" in Intel's docs).
// This method returns the transcoder that is currently connected to the pipe
// output, which can be the general-purpose transcoder tied to the pipe, or
// one of the shared specialized transcoders. The return value depends on how
// we configure the display engine.
virtual TranscoderId connected_transcoder_id() const = 0;
display::DisplayId attached_display_id() const { return attached_display_id_; }
bool in_use() const { return attached_display_id_ != display::kInvalidDisplayId; }
// Display device registers only store image handles / addresses. We should
// convert the handles to corresponding config stamps using the existing
// mapping updated in |ApplyConfig()|.
display::ConfigStamp GetVsyncConfigStamp(const std::vector<uint64_t>& image_handles);
bool attached_edp() const { return attached_edp_; }
registers::Platform platform() const { return platform_; }
void ConfigurePrimaryPlane(uint32_t plane_num, const primary_layer_t* primary, bool enable_csc,
bool* scaler_1_claimed, registers::pipe_arming_regs* regs,
display::ConfigStamp config_stamp,
const SetupGttImageFunc& setup_gtt_image,
const GetImagePixelFormatFunc& get_pixel_format);
void ConfigureCursorPlane(const cursor_layer_t* cursor, bool enable_csc,
registers::pipe_arming_regs* regs, display::ConfigStamp config_stamp);
void SetColorConversionOffsets(bool preoffsets, const float vals[3]);
void ResetActiveTranscoder();
void ResetScaler();
// Borrowed reference to Controller instance
fdf::MmioBuffer* mmio_space_ = nullptr;
display::DisplayId attached_display_id_ = display::kInvalidDisplayId;
bool attached_edp_ = false;
registers::Platform platform_;
PipeId pipe_id_;
PowerWellRef pipe_power_;
// For any scaled planes, this contains the (1-based) index of the active scaler
uint32_t scaled_planes_[PipeIds<registers::Platform::kKabyLake>().size()]
[registers::kImagePlaneCount] = {};
// Configuration stamps that have been applied and are pending eviction.
// The values of the config stamps in this list must be strictly increasing.
// Unused configuration stamps, which are older than all the current config
// stamps used in the display layers, will be evicted from the list on each
// Vsync.
std::list<display::ConfigStamp> pending_eviction_config_stamps_;
// The pipe registers only store the handle (address) of the images that are
// being displayed. We need to keep a mapping from *image handle* to the
// latest *config stamp* where this image is used so that we can know which
// layer has the oldest configuration.
std::unordered_map<uintptr_t, display::ConfigStamp> latest_config_stamp_with_image_;
// If the (there can be at most one) background color layer is enabled on the
// pipe, we need to keep the config stamp of the configuration that enables
// the color layer, so that we can return it on a Vsync event of a frame with
// background color.
// Set to `kInvalidConfigStamp` if there's no background color layer.
display::ConfigStamp config_stamp_with_color_layer_ = display::kInvalidConfigStamp;
class PipeSkylake : public Pipe {
PipeSkylake(fdf::MmioBuffer* mmio_space, PipeId pipe_id, PowerWellRef pipe_power)
: Pipe(mmio_space, registers::Platform::kSkylake, pipe_id, std::move(pipe_power)) {}
~PipeSkylake() override = default;
TranscoderId connected_transcoder_id() const override {
return attached_edp() ? TranscoderId::TRANSCODER_EDP : tied_transcoder_id();
class PipeTigerLake : public Pipe {
PipeTigerLake(fdf::MmioBuffer* mmio_space, PipeId pipe_id, PowerWellRef pipe_power)
: Pipe(mmio_space, registers::Platform::kTigerLake, pipe_id, std::move(pipe_power)) {}
~PipeTigerLake() override = default;
TranscoderId connected_transcoder_id() const override { return tied_transcoder_id(); }
} // namespace i915