blob: 4e2c8a36ab050a55925ae4e3f7d782c756639d09 [file] [log] [blame] [edit]
// 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_DISPLAY_INTERRUPTS_H_
#define SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_DISPLAY_INTERRUPTS_H_
#include <fuchsia/hardware/intelgpucore/c/banjo.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/irq.h>
#include <lib/device-protocol/pci.h>
#include <lib/fit/function.h>
#include <lib/mmio/mmio.h>
#include <lib/sync/cpp/completion.h>
#include <lib/zx/interrupt.h>
#include <threads.h>
#include <zircon/types.h>
#include <bitset>
#include <optional>
#include "src/graphics/display/drivers/intel-display/registers-ddi.h"
#include "src/graphics/display/drivers/intel-display/registers-pipe.h"
namespace intel_display {
class Interrupts {
public:
// 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_monotonic timestamp)>;
using HotplugCallback = fit::function<void(DdiId ddi_id, bool long_pulse)>;
Interrupts();
~Interrupts();
// Copying and moving are not allowed.
Interrupts(const Interrupts&) = delete;
Interrupts& operator=(const Interrupts&) = delete;
Interrupts(Interrupts&&) = delete;
Interrupts& operator=(Interrupts&&) = delete;
// Must be called exactly once.
// Must be called from a driver-runtime managed dispatcher.
//
// `mmio_space` must be non-null and outlive the initialized `Interrupts`
// instance.
zx_status_t Init(PipeVsyncCallback pipe_vsync_callback, HotplugCallback hotplug_callback,
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);
private:
void EnableHotplugInterrupts();
void HandlePipeInterrupt(PipeId pipe_id, zx::time_monotonic timestamp);
void InterruptHandler(async_dispatcher_t* dispatcher, async::IrqBase* irq, zx_status_t status,
const zx_packet_interrupt_t* interrupt);
zx::result<> CancelInterruptHandler();
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_;
// The `irq_handler_dispatcher_` and `irq_handler_` are constant between
// `Init()` and instance destruction. Only accessed on the threads used for
// class initialization and destruction.
fdf::SynchronizedDispatcher irq_handler_dispatcher_;
libsync::Completion irq_handler_dispatcher_shutdown_completed_;
async::IrqMethod<Interrupts, &Interrupts::InterruptHandler> irq_handler_{this};
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 intel_display
#endif // SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_DISPLAY_INTERRUPTS_H_