blob: 8181eb3c1764c4602cb519efd67d78a97db48970 [file] [log] [blame]
// Copyright 2023 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_REGISTERS_ARBITER_H_
#define SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_REGISTERS_ARBITER_H_
#include <lib/stdcompat/bit.h>
#include <zircon/assert.h>
#include <cstdint>
#include <hwreg/bitfields.h>
#include "src/graphics/display/drivers/intel-i915/hardware-common.h"
namespace registers {
// ARB_CTL (Display Arbitration Control 1)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 1 pages 51-53
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 1 pages 13-15
// Kaby Lake: IHD-OS-KBL-Vol 2c-1.17 Part 1 pages 82-83
// Skylake: IHD-OS-KBL-Vol 2c-1.17 Part 1 pages 81-82
class ArbitrationControl : public hwreg::RegisterBase<ArbitrationControl, uint32_t> {
public:
// If true, writes to FBC (framebuffer compression) surfaces wake up RAM.
DEF_BIT(31, framebuffer_compression_writes_wake_memory);
DEF_RSVDZ_BIT(29);
// The HP (high-priority) queue is read after it has this many entries.
//
// This field has a non-trivial encoding. It should be used via the
// `high_priority_queue_watermark()` and `set_high_priority_queue_watermark()`
// helpers.
DEF_FIELD(28, 26, high_priority_queue_watermark_bits);
// Maximum number of LP (low-priority) write requests accepted from a client.
//
// This field has a non-trivial encoding. It should be used via the
// `low_priority_back_to_back_request_limit()` and
// `set_low_priority_back_to_back_request_limit()` helpers.
DEF_FIELD(25, 24, low_priority_back_to_back_request_limit_bits);
// Maximum number of TLB requests issued in one arbitration loop.
//
// This limit applies to TLB (translation lookaside buffer) and VT-D
// (virtualized directed I/O) address translation requests.
//
// This value must not be zero.
DEF_FIELD(23, 20, translation_lookaside_buffer_request_limit);
// Maximum number of TLB requests in-flight.
//
// This limit applies to TLB (translation lookaside buffer) and VT-D
// (virtualized directed I/O) address translation requests.
//
// This value must not be zero.
DEF_FIELD(19, 16, translation_lookaside_buffer_in_flight_request_limit);
// If true, the FBC (framebuffer compression) watermarks are disabled.
DEF_BIT(15, framebuffer_compression_watermarks_disabled);
// Zero on all supported display engines.
//
// This field was used to configure Display Engine-side swizzling of physical
// memory address bits when accessing Y-tiled surfaces. On recent processors,
// this feature has been deprecated in favor of DRAM controller-level address
// swizzling, and the field should be set to 0 indicating no display requests
// address swizzling on these processors.
DEF_FIELD(14, 13, tiled_address_swizzling);
// Maximum number of page breaks in a chain of HP (high-priority) requests.
//
// This value must not be zero.
DEF_FIELD(12, 8, high_priority_request_chain_page_break_limit);
DEF_RSVDZ_BIT(7);
// Maximum number of cachelines in a chain of HP (high-priority) requests.
//
// This value must be greater than 8, which is the size of a DBUF (Display
// Buffer) block.
DEF_FIELD(6, 0, high_priority_request_chain_cache_line_limit);
// Maximum number of LP (low-priority) write requests accepted from a client.
int32_t high_priority_queue_watermark() const {
// The cast and addition will not overflow (causing UB) because the
// underlying field is a 3-bit integer.
return static_cast<int32_t>(high_priority_queue_watermark_bits()) + 1;
}
// See `high_priority_queue_watermark()` for details.
ArbitrationControl& set_high_priority_queue_watermark(int32_t watermark) {
ZX_ASSERT(watermark >= 1);
ZX_ASSERT(watermark <= 8);
const uint32_t raw_watermark = static_cast<uint32_t>(watermark - 1);
return set_high_priority_queue_watermark_bits(raw_watermark);
}
// Maximum number of LP (low-priority) write requests accepted from a client.
//
// After a client reaches this limit of back-to-back requests, re-arbitration
// occurs.
int32_t low_priority_back_to_back_request_limit() const {
// The shift will not overflow (causing UB) because the underlying field is
// a 2-bit integer.
return int32_t{1} << low_priority_back_to_back_request_limit_bits();
}
// See `low_priority_back_to_back_request_limit()` for details.
ArbitrationControl& set_low_priority_back_to_back_request_limit(int32_t request_limit) {
const uint32_t raw_request_limit = TwoBitLog2(request_limit);
return set_low_priority_back_to_back_request_limit_bits(raw_request_limit);
}
// `arbiter_index` zero (0) represents the global arbiter. The following
// indexes represent the numbered arbiters.
//
// Kaby Lake and Skylake only have a global arbiter.
static auto GetForArbiter(int arbiter_index) {
ZX_ASSERT(arbiter_index >= 0);
ZX_ASSERT(arbiter_index <= 2);
if (arbiter_index == 0) {
return hwreg::RegisterAddr<ArbitrationControl>(0x45000);
}
return hwreg::RegisterAddr<ArbitrationControl>(0x45800 - 8 + 8 * arbiter_index);
}
// Helper for setting 2-bit fields that use log2 representation.
static uint32_t TwoBitLog2(int32_t value) {
ZX_ASSERT(value >= 1);
ZX_ASSERT(value <= 8);
ZX_ASSERT((value & (value - 1)) == 0);
return cpp20::countr_zero(static_cast<uint32_t>(value));
}
};
// ARB_CTL (Display Arbitration Control 2)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 1 pages 54-56
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 1 pages 13-15
// Kaby Lake: IHD-OS-KBL-Vol 2c-1.17 Part 1 pages 82-83
// Skylake: IHD-OS-KBL-Vol 2c-1.17 Part 1 pages 81-82
class ArbitrationControl2 : public hwreg::RegisterBase<ArbitrationControl2, uint32_t> {
public:
DEF_RSVDZ_BIT(30);
// Maximum number of write requests accepted from WD (display capture).
//
// This field has a non-trivial encoding. It should be used via the helpers
// `display_capture_write_request_limit()` and
// `set_display_capture_write_request_limit()`.
DEF_FIELD(29, 28, display_capture_write_request_limit_bits);
// Maximum number of write requests accepted from DSB (Display State Buffer).
//
// This field has a non-trivial encoding. It should be used via the helpers
// `display_state_buffer_write_request_limit_tiger_lake()` and
// `set_display_state_buffer_write_request_limit_tiger_lake()`.
DEF_FIELD(27, 26, display_state_buffer_write_request_limit_tiger_lake_bits);
DEF_RSVDZ_FIELD(25, 20);
// Maximum number of requests accepted from "par5".
//
// "par5" does not appear to be documented.
//
// This field does not exist on Kaby Lake or Skylake.
//
// This field has a non-trivial encoding.
DEF_FIELD(19, 18, par5_request_limit_tiger_lake_bits);
// Maximum number of requests accepted from FBC (framebuffer compression).
//
// This field has a non-trivial encoding. It should be used via the helpers
// `framebuffer_compression_request_limit_tiger_lake()` and
// `set_framebuffer_compression_request_limit_tiger_lake()`.
DEF_FIELD(17, 16, framebuffer_compression_request_limit_tiger_lake_bits);
DEF_RSVDZ_FIELD(15, 14);
// If true, a HP request causes the arbiter to accept trickle feed requests.
//
// Trickle feed requests are sent by DBUF (Display Buffer) clients that
// react immediately when a DBUF block that they own frees up. By contrast,
// DBUF clients may send batched requests after a few blocks free up. The
// concept was most recently documented in IHD-OS-VLV-Vol10-04.14 (the
// Valleyview Display Engine PRM).
//
// If this bit is enabled, the arbiter allows trickle feed requests from all
// clients when it receives a HP (high-priority) request from one client.
DEF_BIT(12, high_priority_requests_enable_trickle_feed_requests);
// The maximum number of in-flight LP (low-priority) read transactions.
//
// This field has a non-trivial encoding. It should be used via the helpers
// `max_inflight_low_priority_read_requests()` and
// `set_max_inflight_low_priority_read_requests()`.
DEF_FIELD(10, 9, max_inflight_low_priority_read_requests_bits);
DEF_RSVDZ_FIELD(8, 6);
// The maximum number of in-flight HP (high-priority) read transactions.
//
// This field has a non-trivial encoding. It should be used via the helpers
// `max_inflight_high_priority_read_requests()` and
// `set_max_inflight_high_priority_read_requests()`.
DEF_FIELD(5, 4, max_inflight_high_priority_read_requests_bits);
// If false, the Display Engine always sends requests at isochronous priority.
//
// If true, the Display Engine may issue request at lower priority, which may
// improve performance for other memory-bound workloads. The Display Engine's
// requests will be demoted once the relevant transition watermark is reached.
// If the transition watermark is not enabled, the Display Engine's requests
// are demoted once the DBUF (Display Buffer) is full.
//
// The hardware only reads this bit from the global arbiter's configuration.
// Other arbiters, such as Arbiter 1 and 2 on Tiger Lake, use the global
// arbiter's setting.
DEF_BIT(3, isochronous_priority_control_enabled);
DEF_RSVDZ_BIT(2);
// Minimum RTID queue size required to start HP (high-priority) transactions.
//
// This field has a non-trivial encoding. It should be used via the helpers
// `request_transaction_id_queue_watermark()` and
// `set_request_transaction_id_queue_watermark()`.
DEF_FIELD(1, 0, request_transaction_id_queue_watermark_bits);
// Maximum number of write requests accepted from WD (display capture).
//
// WD (Wireless Display / display capture) transcoders issue LP (low-priority)
// write requests. Re-arbitration occurs after this limit is hit.
int32_t display_capture_write_request_limit() const {
// The shift will not overflow (causing UB) because the underlying field is
// a 2-bit integer.
return int32_t{1} << display_capture_write_request_limit_bits();
}
// See `display_capture_write_request_limit()` for details.
ArbitrationControl2& set_display_capture_write_request_limit(int32_t request_limit) {
const uint32_t raw_request_limit = ArbitrationControl::TwoBitLog2(request_limit);
return set_display_capture_write_request_limit_bits(raw_request_limit);
}
// Maximum number of write requests accepted from DSB (Display State Buffer).
//
// DSB (Display State Buffer) engines issues LP (low-priority) write requests.
// Re-arbitration occurs after this limit is hit.
//
// This field does not exist on Kaby Lake or Skylake.
int32_t display_state_buffer_write_request_limit_tiger_lake() const {
// The shift will not overflow (causing UB) because the underlying field is
// a 2-bit integer.
return int32_t{1} << display_state_buffer_write_request_limit_tiger_lake_bits();
}
// See `display_state_buffer_write_request_limit_tiger_lake()` for details.
ArbitrationControl2& set_display_state_buffer_write_request_limit_tiger_lake(
int32_t request_limit) {
const uint32_t raw_request_limit = ArbitrationControl::TwoBitLog2(request_limit);
return set_display_state_buffer_write_request_limit_tiger_lake_bits(raw_request_limit);
}
// Maximum number of requests accepted from "par5".
//
// The "par5" client / feature does not appear to be documented. Nevertheless,
// re-arbitration occurs after this limit is hit.
//
// This field does not exist on Kaby Lake or Skylake.
int32_t par5_request_limit_tiger_lake() const {
// The shift will not overflow (causing UB) because the underlying field is
// a 2-bit integer.
const int32_t exponential_value = int32_t{1} << par5_request_limit_tiger_lake_bits();
return exponential_value == 8 ? 16 : exponential_value;
}
// See `par5_request_limit_tiger_lake()` for details.
ArbitrationControl2& set_par5_request_limit_tiger_lake(int32_t request_limit) {
ZX_ASSERT(request_limit <= 16);
ZX_ASSERT(request_limit != 8);
const uint32_t raw_request_limit =
ArbitrationControl::TwoBitLog2(request_limit == 16 ? 8 : request_limit);
return set_par5_request_limit_tiger_lake_bits(raw_request_limit);
}
// Maximum number of requests accepted from FBC (framebuffer compression).
//
// The FBC (framebuffer compression) feature issues LP (low-priority) write
// requests to update the compressed framebuffer. Re-arbitration occurs after
// this limit is hit.
//
// This field does not exist on Kaby Lake or Skylake.
int32_t framebuffer_compression_request_limit_tiger_lake() const {
// The shift will not overflow (causing UB) because the underlying field is
// a 2-bit integer.
return int32_t{1} << framebuffer_compression_request_limit_tiger_lake_bits();
}
// See `framebuffer_compression_request_limit_tiger_lake()` for details.
ArbitrationControl2& set_framebuffer_compression_request_limit_tiger_lake(int32_t request_limit) {
const uint32_t raw_request_limit = ArbitrationControl::TwoBitLog2(request_limit);
return set_framebuffer_compression_request_limit_tiger_lake_bits(raw_request_limit);
}
// The maximum number of in-flight LP (low-priority) read transactions.
int32_t max_inflight_low_priority_read_requests() const {
// The cast and addition will not overflow (causing UB) because the
// underlying field is a 2-bit integer.
return static_cast<int32_t>(max_inflight_low_priority_read_requests_bits()) + 1;
}
// See `max_inflight_low_priority_read_requests()` for details.
ArbitrationControl2& set_max_inflight_low_priority_read_requests(int32_t max_requests) {
ZX_ASSERT(max_requests >= 1);
ZX_ASSERT(max_requests <= 8);
const uint32_t raw_max_requests = static_cast<uint32_t>(max_requests - 1);
return set_max_inflight_low_priority_read_requests_bits(raw_max_requests);
}
// The maximum number of in-flight HP (high-priority) read transactions.
int32_t max_inflight_high_priority_read_requests() const {
// The subtraction will not produce a negative number (leading to UB in the
// shift operator) because the underlying field is a 2-bit integer.
return int32_t{1} << (7 - max_inflight_high_priority_read_requests_bits());
}
// See `max_inflight_high_priority_read_requests()` for details.
ArbitrationControl2& set_max_inflight_high_priority_read_requests(int32_t max_requests) {
ZX_ASSERT(max_requests >= 16);
ZX_ASSERT(max_requests <= 128);
ZX_ASSERT((max_requests & (max_requests - 1)) == 0);
const uint32_t raw_max_requests = 7 - cpp20::countr_zero(static_cast<uint32_t>(max_requests));
return set_max_inflight_high_priority_read_requests_bits(raw_max_requests);
}
// Minimum RTID queue size required to start HP (high-priority) transactions.
//
// RTIDs (Request Transaction IDs) are credits issued by the per-processor
// cache coherence coordinator, which is the CHA (combined Caching and Home
// Agent) on recent CPU models. These credits track outstanding transactions
// across the cache coherence bus, which is UPI (Ultra-Path Interconnect) on
// recent CPU models, and QPI (Quick-Path Interconnect) on older models. The
// "RTID" acronym is defined in some processor datasheets, such as document
// 735086 (Ice Lake Xeon processor datasheet, volume 2). The CHA is described
// at a very high level in uncore performance monitoring manuals, such as
// document
//
//
// This watermark is the minimum level of the RTID FIFO (queue) required for
// the arbiter to start HP (high-priority) transactions.
//
// The pseudocode in IHD-OS-TGL-Vol 12-1.22-Rev2.0 "Bandwidth Restrictions" >
// "Available Memory Bandwidth Calculation" on pages 163-166 suggests that
// each memory transaction (on each DRAM channel) requires an RTID.
int32_t request_transaction_id_queue_watermark() const {
// The subtraction will not produce a negative number (leading to UB in the
// shift operator) because the underlying field is a 2-bit integer.
return int32_t{8} << request_transaction_id_queue_watermark_bits();
}
// See `request_transaction_id_queue_watermark()` for details.
ArbitrationControl2& set_request_transaction_id_queue_watermark(int32_t watermark) {
ZX_ASSERT(watermark >= 8);
ZX_ASSERT(watermark <= 32);
ZX_ASSERT((watermark & (watermark - 1)) == 0);
const uint32_t raw_watermark = cpp20::countr_zero(static_cast<uint32_t>(watermark)) - 3;
return set_request_transaction_id_queue_watermark_bits(raw_watermark);
}
// `arbiter_index` zero (0) represents the global arbiter. The following
// indexes represent the numbered arbiters.
//
// Kaby Lake and Skylake only have a global arbiter.
static auto GetForArbiter(int arbiter_index) {
ZX_ASSERT(arbiter_index >= 0);
ZX_ASSERT(arbiter_index <= 2);
if (arbiter_index == 0) {
return hwreg::RegisterAddr<ArbitrationControl2>(0x45004);
}
return hwreg::RegisterAddr<ArbitrationControl2>(0x45804 - 8 + 8 * arbiter_index);
}
};
// BOOTVECTOR
// BW_BUDDY_CTL (Bandwidth Buddy Control)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Rocket Lake: IHD-OS-RKL-Vol 2-7.22 page 30
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 1 page 171
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 page 136
class BandwidthBuddyControl : public hwreg::RegisterBase<BandwidthBuddyControl, uint32_t> {
public:
// If true, the address buddy logic is disabled.
DEF_BIT(31, disabled);
DEF_RSVDZ_BIT(29);
// Time that a regular request (for plane data) waits for a buddy.
//
// Plane data is fetched using HP (high-priority) requests. Each incoming
// request has an associated timer, whose initial value comes from this field.
// The timer tracks the amount of time that a request is stalled waiting for a
// suitable buddy request.
//
// The timer balances the DRAM bandwidth savings obtained by the buddy system
// (reducing the number of DRAM management operations) with the delays
// introduced by stalling requests until suitable buddies come along.
DEF_FIELD(28, 23, plane_data_request_timer);
DEF_RSVDZ_BIT(22);
// Time that a TLB request (for address translation data) waits for a buddy.
//
// Plane data is conceptually stored in graphics virtual memory, using the
// GGTT (Global Graphics Translation Table). Similarly to IA (Intel
// Architecture) CPUs, virtual-to-physical address translations are cached in
// a TLB (translation lookaside buffer). TLB requests occur when fetching
// plane data result in TLB misses, and the TLB controller needs to fetch
// virtual-to-physical address translations from the GGTT.
//
// TLB requests are stalled waiting for suitable buddies, using the same
// mechanism as `plane_data_request_timer`.
DEF_FIELD(21, 16, address_translation_request_timer);
DEF_RSVDZ_FIELD(14, 0);
// Tiger Lake has two bandwidth buddy instances, at indexes 1 and 2.
// Rocket Lake, has a single bandwidth buddy instance, at index 0.
static auto GetForArbiter(int arbiter_index) {
ZX_ASSERT(arbiter_index >= 0);
ZX_ASSERT(arbiter_index <= 2);
return hwreg::RegisterAddr<BandwidthBuddyControl>(0x45130 + 0x10 * arbiter_index);
}
};
// BW_BUDDY_PAGE_MASK (Bandwidth Buddy Page Mask)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// This register is not documented on Kaby Lake or Skylake.
//
// Rocket Lake: IHD-OS-RKL-Vol 2-7.22 page 32
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 1 page 173
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 page 138
class BandwidthBuddyPageMask : public hwreg::RegisterBase<BandwidthBuddyPageMask, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 28);
// The address bits masked for buddy address comparison.
//
// The buddy system determines if two memory requests can be paired by
// comparing bits 36-9 of the requests' physical addresses. However, the
// comparison ignores the bits whose corresponding mask bits in this field are
// set to 1. Conceptually, bits 36-9 in the physical address are ANDed with
// the inverse (NOT) of bits 27-0 in this field before going into the
// comparator.
//
// This field accounts for the system's DRAM configuration. The intent is that
// the buddy system improves DRAM bandwidth efficiency by pairing up memory
// requests in a way that cuts down on DRAM management operations, such as
// opening rows.
DEF_FIELD(27, 0, address_page_mask);
// Tiger Lake has two bandwidth buddy instances, at indexes 1 and 2.
// Rocket Lake, has a single bandwidth buddy instance, at index 0.
static auto GetForArbiter(int arbiter_index) {
ZX_ASSERT(arbiter_index >= 0);
ZX_ASSERT(arbiter_index <= 2);
return hwreg::RegisterAddr<BandwidthBuddyPageMask>(0x45134 + 0x10 * arbiter_index);
}
};
// DEDICATED_PATH_ARB_CREDITS (Dedicated Path Arbiter Credits)
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// Starting with Tiger Lake, the Display Engine has a dedicated path to memory
// through the processor's fabric. This dedicated path is intended to ensure
// that the Display Engine's latency requirements are met even under heavy
// memory contention.
//
// This register configures the credits are used for arbitrating between ABOXes
// (Arbiter Boxes) for streaming HP (high-priority) traffic to the dedicated
// memory path.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 1 page 415
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 page 396
class DedicatedPathArbiterCredits
: public hwreg::RegisterBase<DedicatedPathArbiterCredits, uint32_t> {
public:
// Dedicated memory path credits for ABOX0.
DEF_FIELD(14, 8, arbiter_box1_credits);
// Dedicated memory path credits for ABOX1.
DEF_FIELD(6, 0, arbiter_box0_credits);
static auto Get() { return hwreg::RegisterAddr<DedicatedPathArbiterCredits>(0x100180); }
};
// MBUS_ABOX_CTL (MBus ABox Control)
//
// Does not exist on Kaby Lake or Skylake, which don't have MBus.
//
// ABoxes (Arbiter Boxes) are the attachment points for the arbiters, which are
// configured by the ArbitrationControl (ARB_CTL) registers.
//
// All reserved bits in this register are MBZ (must be zero). So, the register
// can be safely updated without reading it first.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 8-9
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 8-9
class MbusArbiterBoxControl : public hwreg::RegisterBase<MbusArbiterBoxControl, uint32_t> {
public:
// Read-only status bit.
DEF_BIT(31, enabled);
// Read-only address of the box in the ring.
DEF_FIELD(30, 27, ring_stop_address);
// Ignored if `back_to_back_transactions_regulation_enabled` is false.
//
// Used in conjunction with `back_to_back_transaction_delay` to limit the
// number of back-to-back transactions sent from this box.
//
// Zero is not a valid value.
DEF_FIELD(26, 22, max_back_to_back_transactions);
// BW credits used to write to the DBUF (Display Buffer).
//
// These credits are used by the VGA host controller.
DEF_FIELD(21, 20, display_buffer_write_credits);
// B credits used by the Arbiter to read from DBUF (Display Buffer).
//
// These credits are used by the Arbiter, which reads data from DBUF and
// writes it to the main memory as part of FBC (FrameBuffer Compression) and
// WiDi (Display Capture).
DEF_FIELD(19, 16, display_buffer_read_credits);
DEF_RSVDZ_FIELD(15, 14);
// If true, B2B (back-to-back) transaction regulation fields are in effect.
DEF_BIT(13, back_to_back_transactions_regulation_enabled);
// BT credits used by the Arbiter to request DBUF (Display Buffer) trackers.
DEF_FIELD(12, 8, display_buffer_tracker_credits_pool2);
// Number of wait cycles after `max_back_to_back_transactions` is hit.
DEF_FIELD(7, 5, back_to_back_transaction_delay);
// BT credits used by the Arbiter to request DBUF (Display Buffer) trackers.
DEF_FIELD(4, 0, display_buffer_tracker_credits_pool1);
// `arbiter_index` zero (0) represents the global arbiter. The following
// indexes represent the numbered arbiters.
static auto GetForArbiter(int arbiter_index) {
ZX_ASSERT(arbiter_index >= 0);
ZX_ASSERT(arbiter_index <= 2);
if (arbiter_index == 0) {
return hwreg::RegisterAddr<MbusArbiterBoxControl>(0x45038);
}
return hwreg::RegisterAddr<MbusArbiterBoxControl>(0x45044 + 4 * arbiter_index);
}
};
// MBUS_BBOX_CTL (MBus BBox Control)
//
// Does not exist on Kaby Lake or Skylake, which don't have MBus.
//
// BBoxes (Buffer Boxes) are the attachment points for the DBUF (Display Buffer)
// slices.
//
// All reserved bits in this register are MBZ (must be zero). So, the register
// can be safely updated without reading it first.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 10-11
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 10-11
class MbusDisplayBufferBoxControl
: public hwreg::RegisterBase<MbusDisplayBufferBoxControl, uint32_t> {
public:
// Read-only status bit.
DEF_BIT(31, enabled);
// Read-only address of the box in the ring.
DEF_FIELD(30, 27, ring_stop_address);
DEF_RSVDZ_FIELD(26, 25);
// Ignored if `back_to_back_transactions_regulation_enabled` is false.
//
// Used in conjunction with `back_to_back_transaction_delay` to limit the
// number of back-to-back transactions sent from this box.
//
// Zero is not a valid value.
DEF_FIELD(24, 20, max_back_to_back_transactions);
// Number of wait cycles after `max_back_to_back_transactions` is hit.
DEF_FIELD(19, 17, back_to_back_transaction_delay);
// If true, B2B (back-to-back) transaction regulation fields are in effect.
DEF_BIT(16, back_to_back_transactions_regulation_enabled);
DEF_RSVDZ_FIELD(15, 0);
// `slice_index` is 0-based. Index 0 points to DBUF (Display Buffer) Slice 1.
static auto GetForSlice(int slice_index) {
ZX_ASSERT(slice_index >= 0);
ZX_ASSERT(slice_index < 2);
return hwreg::RegisterAddr<MbusDisplayBufferBoxControl>(0x45040 + 4 * slice_index);
}
};
// MBUS_DBOX_CTL (Pipe MBus DBox Control)
//
// Does not exist on Kaby Lake or Skylake, which don't have MBus.
//
// All reserved bits in this register are MBZ (must be zero). So, the register
// can be safely updated without reading it first.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 12-13
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 12-13
class MbusPipeDataBoxControl : public hwreg::RegisterBase<MbusPipeDataBoxControl, uint32_t> {
public:
// Read-only status bit.
DEF_BIT(31, enabled);
// Read-only address of the box in the ring.
DEF_FIELD(30, 27, ring_stop_address);
DEF_RSVDZ_FIELD(26, 25);
// Ignored if `back_to_back_transactions_regulation_enabled` is false.
//
// Used in conjunction with `back_to_back_transaction_delay` to limit the
// number of back-to-back transactions sent from this box.
//
// Zero is not a valid value.
DEF_FIELD(24, 20, max_back_to_back_transactions);
// Number of wait cycles after `max_back_to_back_transactions` is hit.
DEF_FIELD(19, 17, back_to_back_transaction_delay);
// If true, B2B (back-to-back) transaction regulation fields are in effect.
DEF_BIT(16, back_to_back_transactions_regulation_enabled);
// BW credits used by the display pipe to write to the DBUF (Display Buffer).
//
// These credits are used to write data regarding color-clear, WiDi (display
// capture), and FBC (framebuffer compression).
DEF_FIELD(15, 14, display_buffer_write_credits);
DEF_RSVDZ_BIT(13);
// B credits used by the display pipe to read from DBUF (Display Buffer).
//
// The default value (0) is unsuitable for Display Engine operation. The PRM
// recommends setting this field to 12.
DEF_FIELD(12, 8, display_buffer_read_credits);
DEF_RSVDZ_FIELD(7, 4);
// A credits used by the display pipe to make requests to the Arbiter.
//
// Arbiter requests cover pipe data, TLB (address translation lookaside
// buffer), VTd (virtualization for directed IO), and MCS (Multi-sample
// Control Surface, described in Vol 5).
DEF_FIELD(3, 0, arbiter_read_credits);
static auto GetForPipe(i915::PipeId pipe_id) {
// TODO(https://fxbug.dev/42060657): Accept pipe D, once we support it.
ZX_ASSERT(pipe_id >= i915::PipeId::PIPE_A);
ZX_ASSERT(pipe_id <= i915::PipeId::PIPE_C);
const int pipe_index = pipe_id - i915::PipeId::PIPE_A;
return hwreg::RegisterAddr<MbusPipeDataBoxControl>(0x7003c + 0x1000 * pipe_index);
}
};
// MBUS_UBOX_CTL (MBus UBox Control)
//
// Does not exist on Kaby Lake or Skylake, which don't have MBus.
//
// All reserved bits in this register are MBZ (must be zero). So, the register
// can be safely updated without reading it first.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 14-15
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 14-15
class MbusUtilityBoxControl : public hwreg::RegisterBase<MbusUtilityBoxControl, uint32_t> {
public:
// Read-only status bit.
DEF_BIT(31, enabled);
// Read-only address of the box in the ring.
DEF_FIELD(30, 27, ring_stop_address);
DEF_RSVDZ_FIELD(26, 25);
// Ignored if `back_to_back_transactions_regulation_enabled` is false.
//
// Used in conjunction with `back_to_back_transaction_delay` to limit the
// number of back-to-back transactions sent from this box.
//
// Zero is not a valid value.
DEF_FIELD(24, 20, max_back_to_back_transactions);
// Number of wait cycles after `max_back_to_back_transactions` is hit.
DEF_FIELD(19, 17, back_to_back_transaction_delay);
// If true, B2B (back-to-back) transaction regulation fields are in effect.
DEF_BIT(16, back_to_back_transactions_regulation_enabled);
DEF_RSVDZ_FIELD(15, 7);
// A credits used by KVM to make requests to the Arbiter.
//
// These credits are used by the KVM functionality in the CSME (Converged
// Security and Management Engine).
DEF_FIELD(6, 4, arbiter_read_credits);
DEF_RSVDZ_BIT(3);
// B credits used by VGA to read from DBUF (Display Buffer).
DEF_FIELD(2, 0, display_buffer_read_credits);
static auto Get() { return hwreg::RegisterAddr<MbusUtilityBoxControl>(0x4503c); }
};
// PIPE_ARB_CTL (Pipe Arbiter Control)
//
// This register does not exist on Kaby Lake or Skylake.
//
// This register has bits that are reserved but not MBZ (must be zero). So, it
// can only be safely updated via read-modify-write operations.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev2.0 Part 2 pages 669-670
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2 pages 669-670
class PipeArbiterControl : public hwreg::RegisterBase<PipeArbiterControl, uint32_t> {
public:
DEF_RSVDZ_FIELD(31, 21);
// If true, weighted pipe slice arbitration is disabled.
DEF_BIT(20, weighted_arbitration_disabled);
// Number of additional slots added to an arbitration cycle.
//
// During these additional slots, clients are served using round-robin.
DEF_FIELD(18, 16, arbitration_cycle_additional_slots);
DEF_RSVDZ_FIELD(15, 14);
// If true, arbitration configuration in `PlaneControl` (PLANE_CTL) is used.
//
// This field enables the use of the
// `pipe_slice_request_arbitration_slot_count_tiger_lake` field.
// If this field is false, hardware defaults are used instead.
DEF_BIT(13, plane_control_slot_config_enabled);
// If true, the pipe arbiter does not check for block validity.
DEF_BIT(12, block_validity_check_disabled);
// The DSB (Display Stream Buffer) engine service interval, in clock cycles.
//
// This field has a non-trivial encoding.
DEF_FIELD(11, 10, display_stream_buffer_arbitration_interval_bits);
// Number of DBUF (Display Buffer) requests serviced per streamer request.
//
// This field has a non-trivial encoding. It should be used via the
// `display_buffer_requests_per_streamer_request()` and
// `set_display_buffer_requests_per_streamer_request()` helpers.
DEF_FIELD(9, 8, display_buffer_requests_per_streamer_request_bits);
DEF_RSVDZ_FIELD(7, 6);
// Number of microseconds the pipe waits after frame start to drain DBUF data.
DEF_FIELD(5, 0, display_buffer_drain_delay_after_frame_start_us);
// The DSB (Display Stream Buffer) engine service interval, in clock cycles.
//
// This field has a non-trivial encoding.
int32_t display_stream_buffer_arbitration_interval() const {
// The shift will not overflow (causing UB) because the underlying field is
// a 2-bit integer.
return int32_t{16} << display_stream_buffer_arbitration_interval_bits();
}
// See `display_stream_buffer_arbitration_interval()` for details.
PipeArbiterControl& set_display_stream_buffer_arbitration_interval(int32_t clocks) {
ZX_ASSERT(clocks >= 16);
ZX_ASSERT(clocks <= 128);
ZX_ASSERT((clocks & (clocks - 1)) == 0);
const uint32_t raw_clocks = cpp20::countr_zero(static_cast<uint32_t>(clocks >> 4));
return set_display_stream_buffer_arbitration_interval_bits(raw_clocks);
}
// Number of DBUF (Display Buffer) requests serviced per streamer request.
//
// The register's documentation uses the DDB acronym (Display Data Buffer)
// instead of DBUF. IHD-OS-TGL-Vol 12-1.22-Rev2.0 section "Maximum Data Buffer
// Bandwidth" on page 167 contains "display data buffer (DBUF)", which hints
// that DBUF and DDB are synonyms. The hint is confirmed by the intel-i915
// driver code, which uses both "ddb" and "dbuf" in DBUF-related identifiers.
//
// The "streamer" referenced here is most likely the plane's display streamer,
// which issues memory requests when the plane's free DBUF space exceeds its
// watermark. This streamer is mentioned as the "display streamer" or "overlay
// streamer" in older documentation, such as the "FW1 - Display FIFO Watermark
// Control 1" section in IHD-OS-VLV-Vol10-04.14 (the Display PRM for
// ValleyView graphics). Older documentation had specific names ("display",
// "overlay" / "sprite", "cursor") for planes, used the term "display RAM"
// instead of DBUF, and the term "display FIFO" to refer to a plane's DBUF
// allocation. The "display FIFO" concept is briefly covered in the "DSPARB -
// Display Arbitration Control" section in IHD-OS-VLV-Vol10-04.14. These terms
// still appear in current documentation, and in Intel's driver code.
int32_t display_buffer_requests_per_streamer_request() const {
// The shift will not overflow (causing UB) because the underlying field is
// a 2-bit integer.
return int32_t{2} << display_buffer_requests_per_streamer_request_bits();
}
// See `display_buffer_requests_per_streamer_request()` for details.
PipeArbiterControl& set_display_buffer_requests_per_streamer_request(
int32_t display_buffer_requests) {
ZX_ASSERT(display_buffer_requests >= 2);
ZX_ASSERT(display_buffer_requests <= 16);
ZX_ASSERT((display_buffer_requests & (display_buffer_requests - 1)) == 0);
const uint32_t raw_display_buffer_requests =
cpp20::countr_zero(static_cast<uint32_t>(display_buffer_requests >> 1));
return set_display_buffer_requests_per_streamer_request_bits(raw_display_buffer_requests);
}
static auto GetForPipe(i915::PipeId pipe_id) {
// TODO(https://fxbug.dev/42060657): Accept pipe D, once we support it.
ZX_ASSERT(pipe_id >= i915::PipeId::PIPE_A);
ZX_ASSERT(pipe_id <= i915::PipeId::PIPE_C);
const int pipe_index = pipe_id - i915::PipeId::PIPE_A;
return hwreg::RegisterAddr<PipeArbiterControl>(0x70028 + 0x1000 * pipe_index);
}
};
} // namespace registers
#endif // SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_REGISTERS_ARBITER_H_