blob: 2448fc4672e6d74d2180ac405d0e61aa18846838 [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.
#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_PIPE_MANAGER_H_
#define SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_PIPE_MANAGER_H_
#include <lib/mmio/mmio-buffer.h>
#include <iterator>
#include <list>
#include <type_traits>
#include <unordered_map>
#include "src/graphics/display/drivers/intel-i915/pipe.h"
#include "src/graphics/display/drivers/intel-i915/registers-pipe.h"
#include "src/graphics/display/drivers/intel-i915/registers-transcoder.h"
namespace i915 {
class Controller;
template <bool IsConst, template <class, class...> class Container = std::vector>
class PipeIteratorBase {
public:
// Implement `std::iterator_traits`.
using difference_type = int64_t;
using value_type = std::conditional_t<IsConst, const Pipe*, Pipe*>;
using pointer = void;
using reference = std::add_lvalue_reference_t<value_type>;
using iterator_category = std::forward_iterator_tag;
using container_t = Container<std::unique_ptr<Pipe>>;
using container_iterator_t = std::conditional_t<IsConst, typename container_t::const_iterator,
typename container_t::iterator>;
explicit PipeIteratorBase(container_iterator_t it) : it_(it) {}
explicit operator value_type() { return it_->get(); }
value_type operator*() { return it_->get(); }
bool operator!=(const PipeIteratorBase<IsConst>& other) const { return it_ != other.it_; }
bool operator==(const PipeIteratorBase<IsConst>& other) const { return it_ == other.it_; }
PipeIteratorBase<IsConst>& operator++() {
++it_;
return *this;
}
PipeIteratorBase<IsConst> operator++(int) { return PipeIteratorBase<IsConst>(it_++); }
private:
container_iterator_t it_;
};
// `PipeManager` manages state of all `Pipe`s on the display engine.
//
// The set of `Pipe`s is defined at creation and is fixed and static over the
// lifetime of `PipeManager`. Callers can borrow a Pipe instance when they need
// it for display devices, and must return it before `PipeManager` is destroyed.
class PipeManager {
public:
virtual ~PipeManager() = default;
PipeManager(PipeManager&&) = delete;
PipeManager(const PipeManager&) = delete;
// Request an unused Pipe for a new display, and attach the Pipe to |display|.
//
// Returned Pipes are guaranteed to outlive the display; On display removal,
// The Pipe must be recycled by calling |ReturnPipe()|.
//
// Returns |nullptr| if there is no Pipe available.
//
// TODO(https://fxbug.dev/42056163): This is error-prone because the caller has to call
// `ReturnPipe()` to recycle used pipe manually. Instead we should add a
// wrapper class (like `BorrowedPipeRef`) which could automatically return the
// Pipe after use.
Pipe* RequestPipe(DisplayDevice& display);
// Request the Pipe that have been attached to |display| by other drivers
// (i.e. BIOS / bootloader) by reading the pipe's hardware register state, and
// then update the Pipe's state to note that it's attached to |display|.
//
// Returned Pipes are guaranteed to outlive the display; On display removal,
// The Pipe must be recycled by calling |ReturnPipe()|.
//
// Returns |nullptr| if
// - No Pipe has been ever attached to this |display|, or
// - Error occurs when reading the hardware state.
Pipe* RequestPipeFromHardwareState(DisplayDevice& display, fdf::MmioBuffer* mmio_space);
// Reset pipe transcoders that are not actively in use, e.g. due to pipe being
// inactive, or its corresponding pipe currently connects to another
// transcoder.
virtual void ResetInactiveTranscoders() = 0;
// Return unused Pipe back to |PipeManager| when the display device is
// removed; |pipe| must be a return value of previous |RequestPipe| or
// |RequestPipeFromHardwareState| calls.
void ReturnPipe(Pipe* pipe);
// Returns whether there is any new Pipe allocated to displays, or unused
// Pipe gets reset since last |PipeReallocated()| call.
bool PipeReallocated();
// Random accessor and forward iterator so that we can access the pipes
// using <algorithms> methods and range-based for loop.
//
// TODO(https://fxbug.dev/42056164): This (and the pipe iterator class) adds some
// unnecessary complexity to the PipeManager; we can just replace it with a
// method which returns `std::span<Pipe*>` instead.
Pipe* operator[](PipeId idx) const;
Pipe* At(PipeId idx) const;
using PipeIterator = PipeIteratorBase<false>;
using PipeConstIterator = PipeIteratorBase<true>;
PipeIterator begin();
PipeIterator end();
PipeConstIterator begin() const;
PipeConstIterator end() const;
protected:
explicit PipeManager(std::vector<std::unique_ptr<Pipe>> pipes);
// Platform specific functions to get a new available pipe for an arbitrary
// display device. Return |nullptr| if such a pipe is not available.
virtual Pipe* GetAvailablePipe() = 0;
// Platform specific functions to get a pipe that has been bound to this
// DDI (usually by bootloader) for a display device.
// Return |nullptr| if there is no such a pipe or if there is any other
// internal error when loading the hardware state.
virtual Pipe* GetPipeFromHwState(DdiId ddi_id, fdf::MmioBuffer* mmio_space) = 0;
private:
bool pipes_reallocated_ = false;
std::vector<std::unique_ptr<Pipe>> pipes_;
};
// Instantiation of PipeManager for gen9 devices (Skylake, Kaby Lake, etc.)
class PipeManagerSkylake : public PipeManager {
public:
explicit PipeManagerSkylake(Controller* controller);
~PipeManagerSkylake() override = default;
void ResetInactiveTranscoders() override;
private:
static constexpr PipeId kPipeEnums[] = {PipeId::PIPE_A, PipeId::PIPE_B, PipeId::PIPE_C};
Pipe* GetAvailablePipe() override;
Pipe* GetPipeFromHwState(DdiId ddi_id, fdf::MmioBuffer* mmio_space) override;
static std::vector<std::unique_ptr<Pipe>> GetPipes(fdf::MmioBuffer* mmio_space, Power* power);
fdf::MmioBuffer* mmio_space_;
};
// Instantiation of PipeManager for Tiger Lake
class PipeManagerTigerLake : public PipeManager {
public:
explicit PipeManagerTigerLake(Controller* controller);
~PipeManagerTigerLake() override = default;
void ResetInactiveTranscoders() override;
private:
Pipe* GetAvailablePipe() override;
Pipe* GetPipeFromHwState(DdiId ddi_id, fdf::MmioBuffer* mmio_space) override;
static std::vector<std::unique_ptr<Pipe>> GetPipes(fdf::MmioBuffer* mmio_space, Power* power);
fdf::MmioBuffer* mmio_space_;
};
} // namespace i915
#endif // SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_PIPE_MANAGER_H_