blob: 1b8be9879f4c7bd1a1ac6063b97ab7b1c40f1de5 [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_DRIVERS_MSD_INTEL_GEN_SRC_REGISTER_STATE_HELPER_H
#define SRC_GRAPHICS_DRIVERS_MSD_INTEL_GEN_SRC_REGISTER_STATE_HELPER_H
#include <lib/magma/util/short_macros.h>
#include "device_id.h"
#include "instructions.h"
#include "types.h"
// Helper classes for initializing the register state in a context state buffer.
// RegisterStateHelper has state initialization which is common to supported hardware;
// derived classes below provide everything needed for particular hardware.
struct RegisterStateHelper {
static void* register_context_base(void* context_buffer) {
return static_cast<uint8_t*>(context_buffer) + magma::page_size();
}
RegisterStateHelper(EngineCommandStreamerId id, uint32_t mmio_base, uint32_t* state)
: id_(id), mmio_base_(mmio_base), state_(state) {}
virtual ~RegisterStateHelper() = default;
virtual void write_load_register_immediate_headers() { DASSERT(false); }
virtual void write_second_level_batch_buffer_upper_head_pointer() { DASSERT(false); }
virtual void write_second_level_batch_buffer_head_pointer() { DASSERT(false); }
virtual void write_second_level_batch_buffer_state() { DASSERT(false); }
virtual void write_batch_buffer_per_context_pointer() { DASSERT(false); }
virtual void write_indirect_context_pointer(uint32_t gpu_addr, uint32_t size) { DASSERT(false); }
virtual void write_indirect_context_offset(uint32_t context_offset) { DASSERT(false); }
virtual void write_ccid() { DASSERT(false); }
virtual void write_semaphore_token() { DASSERT(false); }
// CTXT_SR_CTL - Context Save/Restore Control Register
void write_context_save_restore_control() {
state_[0x2] = mmio_base_ + 0x244;
constexpr uint32_t kInhibitSyncContextSwitchBit = 1 << 3;
// The helper only populates part of the context state image; the rest is stored
// on context save, and that part should be not be loaded initially.
constexpr uint32_t kContextRestoreInhibitBit = 1;
constexpr uint32_t kBits = kInhibitSyncContextSwitchBit | kContextRestoreInhibitBit;
state_[0x3] = (kBits << 16) | kBits;
}
// RING_BUFFER_HEAD - Ring Buffer Head
void write_ring_head_pointer(uint32_t head) {
state_[0x4] = mmio_base_ + 0x34;
state_[0x5] = head;
}
// RING_BUFFER_TAIL - Ring Buffer Tail
void write_ring_tail_pointer(uint32_t tail) {
state_[0x6] = mmio_base_ + 0x30;
state_[0x7] = tail;
}
// RING_BUFFER_START - Ring Buffer Start
void write_ring_buffer_start(uint32_t gtt_ring_buffer_start) {
DASSERT(magma::is_page_aligned(gtt_ring_buffer_start));
state_[0x8] = mmio_base_ + 0x38;
state_[0x9] = gtt_ring_buffer_start;
}
// RING_BUFFER_CTL - Ring Buffer Control
void write_ring_buffer_control(uint32_t ringbuffer_size) {
constexpr uint32_t kRingValid = 1;
DASSERT(ringbuffer_size >= magma::page_size() && ringbuffer_size <= 512 * magma::page_size());
DASSERT(magma::is_page_aligned(ringbuffer_size));
state_[0xA] = mmio_base_ + 0x3C;
// This register assumes 4k pages
DASSERT(magma::page_size() == 4096);
state_[0xB] = (ringbuffer_size - magma::page_size()) | kRingValid;
}
// BB_ADDR_UDW - Batch Buffer Upper Head Pointer Register
void write_batch_buffer_upper_head_pointer() {
state_[0xC] = mmio_base_ + 0x168;
state_[0xD] = 0;
}
// BB_ADDR - Batch Buffer Head Pointer Register
void write_batch_buffer_head_pointer() {
state_[0xE] = mmio_base_ + 0x140;
state_[0xF] = 0;
}
// BB_STATE - Batch Buffer State Register
void write_batch_buffer_state() {
constexpr uint32_t kAddressSpacePpgtt = 1 << 5;
state_[0x10] = mmio_base_ + 0x110;
state_[0x11] = kAddressSpacePpgtt;
}
// CS_CTX_TIMESTAMP - CS Context Timestamp Count
void write_context_timestamp() {
state_[0x22] = mmio_base_ + 0x3A8;
state_[0x23] = 0;
}
void write_pdp3_upper(uint64_t pdp_bus_addr) {
state_[0x24] = mmio_base_ + 0x28C;
state_[0x25] = magma::upper_32_bits(pdp_bus_addr);
}
void write_pdp3_lower(uint64_t pdp_bus_addr) {
state_[0x26] = mmio_base_ + 0x288;
state_[0x27] = magma::lower_32_bits(pdp_bus_addr);
}
void write_pdp2_upper(uint64_t pdp_bus_addr) {
state_[0x28] = mmio_base_ + 0x284;
state_[0x29] = magma::upper_32_bits(pdp_bus_addr);
}
void write_pdp2_lower(uint64_t pdp_bus_addr) {
state_[0x2A] = mmio_base_ + 0x280;
state_[0x2B] = magma::lower_32_bits(pdp_bus_addr);
}
void write_pdp1_upper(uint64_t pdp_bus_addr) {
state_[0x2C] = mmio_base_ + 0x27C;
state_[0x2D] = magma::upper_32_bits(pdp_bus_addr);
}
void write_pdp1_lower(uint64_t pdp_bus_addr) {
state_[0x2E] = mmio_base_ + 0x278;
state_[0x2F] = magma::lower_32_bits(pdp_bus_addr);
}
void write_pdp0_upper(uint64_t pdp_bus_addr) {
state_[0x30] = mmio_base_ + 0x274;
state_[0x31] = magma::upper_32_bits(pdp_bus_addr);
}
void write_pdp0_lower(uint64_t pdp_bus_addr) {
state_[0x32] = mmio_base_ + 0x270;
state_[0x33] = magma::lower_32_bits(pdp_bus_addr);
}
// R_PWR_CLK_STATE - Render Power Clock State Register
void write_render_power_clock_state() {
DASSERT(id_ == RENDER_COMMAND_STREAMER);
state_[0x42] = mmio_base_ + 0x0C8;
state_[0x43] = 0;
}
EngineCommandStreamerId id_;
uint32_t mmio_base_;
uint32_t* state_;
};
// Render command streamer pp.25:
// https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-kbl-vol07-3d_media_gpgpu.pdf
// Video command streamer pp.15:
// https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-kbl-vol03-gpu_overview.pdf
struct RegisterStateHelperGen9 : public RegisterStateHelper {
// From INDIRECT_CTX_OFFSET register, p.1070:
// https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-kbl-vol02c-commandreference-registers-part1.pdf
static constexpr uint64_t kIndirectContextOffsetGen9 = 0x26;
RegisterStateHelperGen9(EngineCommandStreamerId id, uint32_t mmio_base, uint32_t* state)
: RegisterStateHelper(id, mmio_base, state) {}
void write_load_register_immediate_headers() override {
// Loads are at odd indices because no-op precedes each.
state_[0x1] = MiLoadDataImmediate::header(14, /*force_posted=*/true);
DASSERT(state_[0x1] == 0x1100101B);
state_[0x21] = MiLoadDataImmediate::header(9, /*force_posted=*/true);
DASSERT(state_[0x21] == 0x11001011);
switch (id_) {
case RENDER_COMMAND_STREAMER:
state_[0x41] = MiLoadDataImmediate::header(1, /*force_posted=*/false);
DASSERT(state_[0x41] == 0x11000001);
break;
case VIDEO_COMMAND_STREAMER:
break;
}
}
// SBB_ADDR_UDW - Second Level Batch Buffer Upper Head Pointer Register
void write_second_level_batch_buffer_upper_head_pointer() override {
state_[0x12] = mmio_base_ + 0x11C;
state_[0x13] = 0;
}
// SBB_ADDR - Second Level Batch Buffer Head Pointer Register
void write_second_level_batch_buffer_head_pointer() override {
state_[0x14] = mmio_base_ + 0x114;
state_[0x15] = 0;
}
// SBB_STATE - Second Level Batch Buffer State Register
void write_second_level_batch_buffer_state() override {
state_[0x16] = mmio_base_ + 0x118;
state_[0x17] = 0;
}
// BB_PER_CTX_PTR - Batch Buffer Per Context Pointer
void write_batch_buffer_per_context_pointer() override {
state_[0x18] = mmio_base_ + 0x1C0;
state_[0x19] = 0;
}
// INDIRECT_CTX - Indirect Context Pointer
void write_indirect_context_pointer(uint32_t gpu_addr, uint32_t size) override {
DASSERT((gpu_addr & 0x3F) == 0);
uint32_t size_in_cache_lines = size / DeviceId::cache_line_size();
DASSERT(size_in_cache_lines < 64);
state_[0x1A] = mmio_base_ + 0x1C4;
state_[0x1B] = gpu_addr | size_in_cache_lines;
}
// INDIRECT_CTX_OFFSET - Indirect Context Offset
void write_indirect_context_offset(uint32_t context_offset) override {
DASSERT((context_offset & ~0x3FF) == 0);
state_[0x1C] = mmio_base_ + 0x1C8;
state_[0x1D] = context_offset << 6;
}
void write_ccid() override {}
void write_semaphore_token() override {}
};
// https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-tgl-vol08-command_stream_programming_0.pdf
// p.49
// https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-tgl-vol09-renderengine_0.pdf
// p.54
struct RegisterStateHelperGen12 : public RegisterStateHelper {
// From INDIRECT_CTX_OFFSET register, p.1245:
// https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-tgl-vol02c-commandreference-registers-part1_0.pdf
static constexpr uint64_t kIndirectContextOffsetGen12 = 0x0D;
RegisterStateHelperGen12(EngineCommandStreamerId id, uint32_t mmio_base, uint32_t* state)
: RegisterStateHelper(id, mmio_base, state) {}
void write_load_register_immediate_headers() override {
// Loads are at odd indices because no-op precedes each.
state_[0x1] =
MiLoadDataImmediate::header(13, /*force_posted=*/true) | MiLoadDataImmediate::kAddMmioBase;
DASSERT(state_[0x1] == 0x11081019);
state_[0x21] =
MiLoadDataImmediate::header(9, /*force_posted=*/true) | MiLoadDataImmediate::kAddMmioBase;
DASSERT(state_[0x21] == 0x11081011);
switch (id_) {
case RENDER_COMMAND_STREAMER:
state_[0x41] = MiLoadDataImmediate::header(1, /*force_posted=*/false) |
MiLoadDataImmediate::kAddMmioBase;
DASSERT(state_[0x41] == 0x11080001);
break;
case VIDEO_COMMAND_STREAMER:
break;
}
}
// BB_PER_CTX_PTR - Batch Buffer Per Context Pointer
void write_batch_buffer_per_context_pointer() override {
state_[0x12] = mmio_base_ + 0x1C0;
state_[0x13] = 0;
}
// INDIRECT_CTX - Indirect Context Pointer
void write_indirect_context_pointer(uint32_t gpu_addr, uint32_t size) override {
DASSERT((gpu_addr & 0x3F) == 0);
uint32_t size_in_cache_lines = size / DeviceId::cache_line_size();
DASSERT(size_in_cache_lines < 64);
state_[0x14] = mmio_base_ + 0x1C4;
state_[0x15] = gpu_addr | size_in_cache_lines;
}
// INDIRECT_CTX_OFFSET - Indirect Context Offset
void write_indirect_context_offset(uint32_t context_offset) override {
DASSERT((context_offset & ~0x3FF) == 0);
state_[0x16] = mmio_base_ + 0x1C8;
state_[0x17] = context_offset << 6;
}
// CCID
void write_ccid() override {
state_[0x18] = mmio_base_ + 0x180;
state_[0x19] = 0;
}
// SEMAPHORE_TOKEN
void write_semaphore_token() override {
state_[0x1A] = mmio_base_ + 0x2B4;
state_[0x1B] = 0;
}
void write_second_level_batch_buffer_upper_head_pointer() override {}
void write_second_level_batch_buffer_head_pointer() override {}
void write_second_level_batch_buffer_state() override {}
};
#endif