blob: 0cc59699df892b78839552acefec5796fb2fb451 [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/intelgpucore/c/banjo.h>
#include <lib/device-protocol/pci.h>
#include <lib/fit/function.h>
#include <lib/mmio/mmio.h>
#include <lib/zx/interrupt.h>
#include <threads.h>
#include <zircon/types.h>
#include <bitset>
#include <optional>
#include <fbl/macros.h>
#include "src/graphics/display/drivers/intel-i915/registers-ddi.h"
#include "src/graphics/display/drivers/intel-i915/registers-pipe.h"
namespace i915 {
class Interrupts {
// Callbacks that are invoked on various interrupt types.
// All interrupt callbacks are currently run on the same thread (the internal
// thread dedicated to handling interrupt). However, implementations must be
// thread-safe, and not rely on any assumptions around the threading model.
using PipeVsyncCallback = fit::function<void(PipeId, zx_time_t)>;
using HotplugCallback = fit::function<void(DdiId ddi_id, bool long_pulse)>;
// The lifetimes of |dev|, |pci|, and |mmio_space| must outlast the initialized Interrupts
// instance.
zx_status_t Init(PipeVsyncCallback pipe_vsync_callback, HotplugCallback hotplug_callback,
zx_device_t* dev, const ddk::Pci& pci, fdf::MmioBuffer* mmio_space,
uint16_t device_id);
void FinishInit();
void Resume();
void Destroy();
// Enable or disable interrupt generation from `pipe`.
// This method enables and disables all the pipe-level interrupts that we are
// prepared to handle.
// Transcoder VSync (vertical sync) interrupts trigger callbacks to the
// PipeVsyncCallback provided to `Init()`. The callbacks are performed on the
// internal thread dedicated to interrupt handling.
void EnablePipeInterrupts(PipeId pipe_id, bool enable);
// The GPU driver uses this to plug into the interrupt stream.
// On Tiger Lake, `gpu_callback` will be called during an interrupt
// from the graphics hardware if the Graphics Primary Interrupt register
// indicates there are GT interrupts pending.
// On Skylake and Kaby Lake, `gpu_callback` will be called during an interrupt
// from the graphics hardware if the Display Interrupt Control register has
// any bits in `gpu_interrupt_mask` set.
zx_status_t SetGpuInterruptCallback(const intel_gpu_core_interrupt_t& gpu_interrupt_callback,
uint32_t gpu_interrupt_mask);
int IrqLoop();
void EnableHotplugInterrupts();
void HandlePipeInterrupt(PipeId pipe_id, zx_time_t timestamp);
PipeVsyncCallback pipe_vsync_callback_;
HotplugCallback hotplug_callback_;
fdf::MmioBuffer* mmio_space_ = nullptr;
mtx_t lock_;
// Initialized by |Init|.
zx::interrupt irq_;
fuchsia_hardware_pci::InterruptMode irq_mode_;
std::optional<thrd_t> irq_thread_; // Valid while irq_ is valid.
uint16_t device_id_;
intel_gpu_core_interrupt_t gpu_interrupt_callback_ __TA_GUARDED(lock_) = {};
uint32_t gpu_interrupt_mask_ __TA_GUARDED(lock_) = 0;
} // namespace i915