blob: b1435046749bc1f2079a917030175af0d4a16a91 [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_REGISTERS_PIPE_SCALER_H_
#define SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_REGISTERS_PIPE_SCALER_H_
#include <lib/ddk/debug.h>
#include <zircon/assert.h>
#include <cmath>
#include <optional>
#include <vector>
#include <hwreg/bitfields.h>
#include "src/graphics/display/drivers/intel-i915/hardware-common.h"
namespace registers {
// PS_CTRL (Pipe Scaler Control) for Skylake / Kaby Lake
//
// A Pipe Scaler can be used to scale the output of a display pipe or a display
// plane. It can scale up / down the resolution and / or scale up the
// downsampled chroma pixels or subplanes (for YUV images).
//
// Pipe A and B has two scalers, and Pipe C has one scaler. Each scaler can
// operate on the output of the entire pipe, or on the output of any of its
// universal planes (but not the cursor plane).
//
// This register is double buffered. See PipeScalerWindowSize for arming and
// dis-arming double-buffer updates.
//
// 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.
//
// Kaby Lake: IHD-OS-KBL-Vol 2c-1.17 Part 2 Pages 647-650
// Skylake: IHD-OS-SKL-Vol 2c-05.16 Part 2, Pages 640-643
class PipeScalerControlSkylake : public hwreg::RegisterBase<PipeScalerControlSkylake, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x68180;
// Enables the scaler.
//
// Before enabling the scaler, software should make sure that the scaler
// configuration fulfills all constraints as specified in PS_CTRL register
// documentation.
DEF_BIT(31, is_enabled);
enum class ScalerMode : uint32_t {
// Supports filter size 7x5 for up to 2048 horizontal source sizes.
// For larger size the filter size is automatically switched to 5x3.
kDynamic = 0b00,
// Supports filter size 7x5. Other scalers must be disabled in this mode.
// Only supported by pipe A and pipe B.
k7x5 = 0b01,
// Required to feed NV12 data into a plane. Does chroma up-scaling and
// size scaling.
// Supports filter size 5x3.
// This value is only documented in Kaby Lake but also mentioned in Skylake.
kNv12 = 0b10,
};
DEF_ENUM_FIELD(ScalerMode, 29, 28, mode);
// Selects the index of the plane where the output is scaled. An index of 0
// indicates that the output of the whole pipe is scaled.
//
// The value of `scaled_plane_index` must not exceed the number of
// planes (excluding cursor plane) supported by the pipe. On Kaby Lake and
// Skylake, each pipe has 3 non-cursor planes.
//
// The caller must guarantee that the plane / pipe fulfills all the
// constraints below:
// - The input size of the pipe / plane must be at least 8 scanlines.
// - IF (Interlaced fetch) mode must be disabled.
// - Keying can only be enabled if the scaling factor is 1.
// - The pixel format must not be 8-bit indexed or XR_BIAS.
// - Floating point source pixel values must be within the [0.0, 1.0] range.
DEF_FIELD(27, 25, scaled_plane_index);
enum class FilterSelection : uint32_t {
// Medium (Median?) filter.
//
// It guarantees that the image is unfiltered when the scaling factor is 1.
//
// The Programmer's Reference Manual (or The reference documentation) does
// not have any further details on this filter.
kMedium = 0b00,
// Same as `kMedium`.
//
// On other display engine models, this value selects programmable
// filtering.
kMedium2 = 0b01,
// Edge Enhance filter.
//
// The Programmer's Reference Manual (or The reference documentation) does
// not have any further details on this filter.
kEdgeEnhance = 0b10,
// Bilinear filter. Scales the image by performing bilinear interpolation.
kBilinear = 0b11,
};
DEF_ENUM_FIELD(FilterSelection, 24, 23, filter_selection);
// Minimum supported horizontal and vertical sizes, in pixels.
// TODO(https://fxbug.dev/42071707): Move all the pipe scaler limits to a separated
// class.
static constexpr uint32_t kMinSrcSizePx = 8;
// Maximum supported horizontal size, in pixels.
static constexpr uint32_t kMaxSrcWidthPx = 4096;
// Number of scalers available in Pipe A and Pipe B.
// TODO(https://fxbug.dev/42071707): This can be refactored into a static method
// taking pipe and platform as its input.
static constexpr uint32_t kPipeABScalersAvailable = 2;
// Number of scalers available in Pipe C.
static constexpr uint32_t kPipeCScalersAvailable = 1;
// Maximum upscaling / downscaling ratio under 7x5 mode.
// TODO(https://fxbug.dev/42071707): This can be refactored into a static method
// taking scaling mode and size as its input.
static constexpr float k7x5MaxRatio = 2.99f;
// Maximum upscaling / downscaling ratio under dynamic mode, for image sizes
// up to 2048 pixels.
static constexpr float kDynamicMaxRatio = 2.99f;
// Maximum vertical upscaling / downscaling ratio under dynamic mode, for
// image sizes greater than 2048 pixels.
static constexpr float kDynamicMaxVerticalRatio2049 = 1.99f;
};
// PS_CTRL (Pipe Scaler Control) for Tiger Lake
//
// A pipe Scaler can be used to scale the output of a display pipe or a display
// plane. It can scale up / down the resolution and / or scale up the
// downsampled chroma pixels or subplanes (for YUV images).
//
// Each pipe has two scalers and they can be assigned to any plane (except for
// color) or the display output.
//
// This register is double buffered. See PipeScalerWindowSize for arming and
// dis-arming double-buffer updates.
//
// 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-Rev 2.0 Part 2, Pages 998-1003
class PipeScalerControlTigerLake
: public hwreg::RegisterBase<PipeScalerControlTigerLake, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x68180;
// Enables the pipe scaler.
//
// Before enabling the scaler, software should make sure that the scaler
// configuration fulfills all the scaler constraints.
DEF_BIT(31, is_enabled);
// If true, the scaler performs YUV chroma upsampling while scaling the
// output, which is also called "planar mode" in some documentation.
//
// This bit must be true if and only if the following conditions are met:
// - The scaler must be bound to a universal plane instead of a pipe.
// - The plane it binds to must be an SDR plane (Plane 4 or 5).
// - The plane's active image must be of YUV 420 format.
DEF_BIT(29, chroma_upscaling_enabled);
// Enables the "Adaptive filtering" mode of the pipe scaler.
//
// When set to true, a multi-threshold adaptive filter will be used for
// vertical and horizontal filtering. The `filter_selection` field will be
// ignored, instead `adaptive_filter_selection` will be used to choose the
// filter type.
//
// There are two sets of adaptive filtering thresholds for each pipe scaler.
// Threshold values (in `PipeScalerAdaptiveFilterThresholds` register) and
// threshold set selection (in `*_filter_set` field) must be programmed before
// this bit being enabled.
DEF_BIT(28, adaptive_filtering_enabled);
// Selects the index of the plane where the output is scaled. An index of 0
// indicates that the output of the whole pipe is scaled.
//
// The value of `scaled_plane_index` must not exceed the number of
// planes supported by the pipe. On Tiger Lake, each pipe has 7 planes.
//
// The caller must guarantee that the plane / pipe fulfills all the
// constraints below:
// - The input size of the pipe / plane must be at least 8 scanlines.
// - IF (Interlaced fetch) mode must be disabled.
// - Keying can only be enabled if the scaling factor is 1.
// - The pixel format must not be 8-bit indexed or XR_BIAS.
// - Floating point source pixel values must be within the [0.0, 1.0] range.
// - For HDR planes (Plane 1 - 3), the `plane_scaling_enabled` field of the
// `PLANE_CUS_CTL` register must be enabled.
DEF_FIELD(27, 25, scaled_plane_index);
enum class NormalFilterSelection : uint32_t {
// Medium (Median?) filter.
//
// It guarantees that the image is unfiltered when the scaling factor is 1.
//
// The Programmer's Reference Manual (or The reference documentation) does
// not have any further details on this filter.
kMedium = 0b00,
// Programmed filter.
//
// Drivers can scale images using different scaling filters with hardware
// acceleration under this mode . A typical usage of programmed filters is
// to implement nearest-neighbor scaling.
//
// The filter has 7 taps and it can have different coefficients on its 17
// phases; so each coefficient set has totally 119 coefficients, and each
// scaler can store 2 sets of programmed coefficients. All the coefficients
// can be set using PS_COEF_INDEX and PS_COEF_DATA registers.
//
// Horizontal filters and vertical filters can be configured to use
// their individual coefficient sets. For YUV planar images, Y plane filters
// and UV plane filters can also be configured to use their own coefficient
// sets.
//
// Tiger Lake: Section "Scaler Programmed Coefficients",
// IHD-OS-TGL-Vol 12-1.22-Rev 2.0 Part 2, Pages 255-256.
kProgrammed = 0b01,
// Edge Enhance filter.
//
// The Programmer's Reference Manual (or The reference documentation) does
// not have any further details on this filter.
kEdgeEnhance = 0b10,
// Bilinear filter. Scales the image by performing bilinear interpolation.
kBilinear = 0b11,
};
// Selects the filter to use for the non-adaptive filter.
//
// This field only works on non-adaptive mode. If `adaptive_filtering_enabled`
// is true, this field will be ignored and `adaptive_filter_selection` will
// be used instead.
DEF_ENUM_FIELD(NormalFilterSelection, 24, 23, normal_filter_selection);
enum class AdaptiveFilterSelection : uint32_t {
// Medium (Median?) filter. Same as `kMedium` in NormalFilterSelection.
kMedium = 0b00,
// Edge enhanced filter. Same as `kEdgeEnhance` in NormalFilterSelection.
kEdgeEnhance = 0b10,
};
// Selects the filter to use for the adaptive filter.
//
// This field only works on adaptive mode. If `adaptive_filtering_enabled`
// is false, this field will be ignored and `normal_filter_selection` will
// be used instead.
DEF_ENUM_FIELD(AdaptiveFilterSelection, 22, 22, adaptive_filter_selection);
// This enum class specifies the scaler interface on the display pipeline that
// the pipe scaler binds to.
//
// Tiger Lake: Section "Pipes", IHD-OS-TGL-Vol 12-1.22-Rev 2.0 Part 2, Pages 117
enum class PipeScalerLocation : uint32_t {
// Scale the pipe output after the second (output) color space conversion
// ("Output CSC" in the display pipeline diagram), which occurs after gamma
// look-up table process ("Post-CSC Gamma" in the diagram) and other gamma
// enhancements.
//
// The scaling occurs after de-gamma and gamma, thus the luminance value is
// still gamma-encoded, so the scaler operates in a non-linear color space.
kAfterOutputColorSpaceConversion = 0b0,
// Scale the pipe output after de-gamma look-up table (Pre-CSC Gamma) and
// the first color space conversion (the "CSC" block in the display pipeline
// diagram).
//
// The scaling occurs after de-gamma where the luminance value gets
// linearized, so the scaler operates in a linear color space.
kAfterColorSpaceConversion = 0b1,
};
// Specifies the scaler interface on the display pipeline that the pipe
// scaler binds to. See `PipeScalerLocation` for details.
//
// This field is effective only when the scaler is bound to the pipe, i.e.
// `scaler_binding_selection` field is 0.
DEF_ENUM_FIELD(PipeScalerLocation, 21, 21, pipe_scaler_location);
DEF_RSVDZ_BIT(18);
DEF_RSVDZ_BIT(16);
DEF_RSVDZ_BIT(14);
DEF_RSVDZ_FIELD(11, 10);
// If true, double-buffer updates can be disabled for this plane.
//
// This field applies when the DOUBLE_BUFFER_CTL register is used to disable
// the double-buffering of all the resources that allow disabling.
DEF_BIT(9, double_buffer_update_disabling_allowed);
// Selects the Y plane surface matching the UV plane selected in
// `scaled_plane_index`.
//
// This field is effective only if planar mode is enabled.
//
// Only the following values are valid for this field:
// - 6 (0b110): indicating Plane 6 is used as input Y plane;
// - 7 (0b111): indicating Plane 7 is used as input Y plane.
//
// `y_plane_binding()` and `set_y_plane_binding()` helper methods can be used
// to get / set the value of this field.
DEF_FIELD(7, 5, y_plane_binding_raw);
// Helper method to get the value of this field with validity check.
uint32_t y_plane_binding() const {
switch (y_plane_binding_raw()) {
case 6:
case 7:
// Valid values.
break;
default:
zxlogf(WARNING, "Scaler bound to an invalid Y plane (%u)", y_plane_binding_raw());
break;
}
return y_plane_binding_raw();
}
// Helper method to set the value of this field with validity check.
PipeScalerControlTigerLake& set_y_plane_binding(uint32_t plane_id) {
ZX_ASSERT_MSG(plane_id == 6 || plane_id == 7,
"Cannot bind non-Y plane (%u) for YUV scaling; only Plane 6 and 7 are supported",
plane_id);
return set_y_plane_binding_raw(plane_id);
}
// Selects the filter coefficient / threshold set used by the *vertical*
// filter for the Y semi-plane bound to the scaler in YUV planar mode.
//
// It's used only in the following conditions:
// - When `chrome_upsampling_enabled` is true and `adaptive_filter_enabled`
// is true, it indicates the adaptive filter threshold set index for Y
// plane scaling filter.
// - When `chrome_upsampling_enabled` is true, adaptive filtering is
// disabled and `normal_filter_select` is `kProgrammed`, it indicates the
// programmed filter coefficient set index for Y plane scaling filter.
// Otherwise, this field will be ignored.
DEF_BIT(4, y_plane_vertical_filter_set);
// Selects the filter coefficient / threshold set used by the *horizontal*
// filter for the Y semi-plane bound to the scaler in YUV planar mode.
//
// The semantics of this field is similar to
// `y_plane_vertical_filter_set_selection` but it applies to the horizontal
// filter instead.
DEF_BIT(3, y_plane_horizontal_filter_set);
// Selects the filter coefficient / threshold set used by the *vertical*
// filter for the plane (or UV semi-plane, if `chroma_upscaling_enabled`
// is true) or pipe bound to the scaler.
//
// It's used in the following conditions:
// - If `adaptive_filter_enabled` is true, this field indicates the index of
// the adaptive filter threshold set.
// - If `adaptive_filter_enabled` is false and `normal_filter_select` is
// `kProgrammed`, this field indicates the selected filter coefficient set.
// Otherwise, this field is ignored.
DEF_BIT(2, vertical_filter_set);
// Selects the filter coefficient / threshold set used by the *horizontal*
// filter for the plane (or UV semi-plane, if `chroma_upscaling_enabled` is
// true) or pipe bound to the scaler.
//
// The semantics of this field is similar to
// `vertical_filter_set_selection` but it applies to the horizontal
// filter instead.
DEF_BIT(1, horizontal_filter_set);
DEF_RSVDZ_BIT(0);
};
// PS_ADAPTIVE_CTRL (Pipe Scaler Adaptive Filter Thresholds)
//
// Each scaler has 2 sets of adaptive filter thresholds that scaler can select
// for filters on each dimension and each semi-plane when adaptive filter is
// enabled for the scaler.
//
// This register is double buffered. See PipeScalerWindowSize for arming and
// dis-arming double-buffer updates.
//
// This register is not documented in Skylake and Kaby Lake.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev 2.0 Part 2, Pages 989-991.
// DG1: IHD-OS-DG1-Vol 2c-2.21 Part 2, Pages 1026-1028.
class PipeScalerAdaptiveFilterThresholds
: public hwreg::RegisterBase<PipeScalerAdaptiveFilterThresholds, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x681A8;
DEF_RSVDZ_FIELD(31, 24);
// The third threshold value in adaptive filtering.
// The recommended value of this field is 0x3c.
DEF_FIELD(23, 16, threshold3);
// The second threshold value in adaptive filtering.
// The recommended value of this field is 0x2d.
DEF_FIELD(15, 8, threshold2);
// The first threshold value in adaptive filtering.
// The recommended value of this field is 0x1e.
DEF_FIELD(7, 0, threshold1);
};
// PS_WIN_POS (Pipe Scaler Window Position)
//
// The scaler outputs the scaled contents to the scaler window, a rectangular
// region specified by `PipeScalerWindowPosition` and `PipeScalerWindowSize`
// on the output surface.
//
// This register specifies the location of the top-left corner. "x" and "y"
// are relative to the display device, thus rotation / flipping of planes and
// pipe doesn't affect the order of x and y.
//
// This register and `PipeScalerWindowSize` must be set so that the whole
// scaler window is within the output surface:
//
// For plane scaling, it outputs to the pipe source, so
// x_position + x_size <= PipeSourceSize.horizontal_source_size
// y_position + y_size <= PipeSourceSize.vertical_source_size
// must be satisfied.
//
// For pipe scaling, it outputs to the transcoder, so
// x_position + x_size <= PipeActiveSize.x_size
// y_position + y_size <= PipeActiveSize.y_size
//
// If the pipe is not joined to other pipes,
// PipeActiveSize.x_size = TranscoderHorizontalTotal.active_size
// PipeActiveSize.y_size = TranscoderVerticalTotal.active_size
//
// TODO(liyl): The documentation is unclear how the pipe active size is defined
// in the case of joined pipes (whether a division is needed).
// otherwise,
// PipeActiveSize.x_size = TranscoderHorizontalTotal.active_size / #(joined pipes)
// + PipeSeamExcess.left_excess_amount + PipeSeamExcess.right_excess_amount
// PipeActiveSize.y_size = TranscoderVerticalTotal.active_size
// Note that the excess amount must be taken into account when merging
// pipes' output to a single transcoder.
//
// This register is double buffered. See PipeScalerWindowSize for arming and
// dis-arming double-buffer updates.
//
// This register's reserved fields are all MBZ (must be zero). So, this register
// can be safely written without reading it first.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev 2.0 Part 2, Pages 1021-1022
// Kaby Lake: IHD-OS-KBL-Vol 2c-1.17 Part 2, Pages 666-667
class PipeScalerWindowPosition : public hwreg::RegisterBase<PipeScalerWindowPosition, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x68170;
DEF_RSVDZ_FIELD(31, 29);
// Horizontal (x) position of the left of the rectangle.
// Must be even for YUV planes / pipes.
DEF_FIELD(28, 16, x_position);
DEF_RSVDZ_FIELD(15, 13);
// Vertical (y) position of the top of the rectangle.
// Must be even for YUV planes / pipes, or for interlaced output.
DEF_FIELD(12, 0, y_position);
};
// Pipe Scaler Programmable Coefficient Data Format (SCALER_COEFFICIENT_FORMAT)
//
// The pipe scaler coefficients use SCALER_COEFFICIENT_FORMAT to store
// coefficient values. This is a signed floating point format with 2 exponent
// bits and 9 mantissa bits, and uses complement representation same as the
// scaled number for negative values.
//
// The coefficient value =
// (-1) ^ (is_negative) * (mantissa / 2 ^ 9) * (1 - exponent).
//
// Tiger Lake: IHD-OS-TGL-Vol 2d-12.21, Page 868.
// Lakefield: IHD-OS-LKF-Vol 2d-5.21, Page 899.
class PipeScalerCoefficientFormat
: public hwreg::RegisterBase<PipeScalerCoefficientFormat, uint32_t> {
public:
// Sign bit.
DEF_BIT(15, is_negative);
// Unsigned 2-bit exponent field.
// The exponent part is 2 ^ (1 - exponent).
DEF_FIELD(13, 12, exponent);
// Mantissa.
// The mantissa part is 0.bbbbbbbbb (uint32(mantissa) / 2 ^ 9).
DEF_FIELD(11, 3, mantissa);
int x2048() const {
return (static_cast<int32_t>(mantissa()) << (3 - exponent())) *
(1 - 2 * static_cast<int32_t>(is_negative()));
}
};
// PS_COEF_DATA (Pipe Scaler Programmable Coefficient Data)
//
// Each scaler has 2 sets of programmable filter coefficients, each of which
// containing 17 (phases) x 7 (taps) = 119 coefficient values. Each coefficient
// value has 16 bits in storage and is of type PipeScalerCoefficientFormat.
//
// To read / write the value of the coefficients, the PS_COEF_INDEX register of
// the scaler coefficient set must be set (or auto-incremented) first, and then
// a pair of 16-bit coefficient values can be read from / written to this
// register.
//
// The coefficients must be written before its value being used or the
// programmable filter being used. Otherwise the filter behavior is undefined.
//
// The coefficient data arrays are double buffered. Writing to the index / data
// register will update the buffered value, and writing to
// `PipeScalerWindowSize` will trigger the double buffering arm so that the
// buffered values will be applied at the start of the next vertical blank.
//
// This register's reserved fields are all MBZ (must be zero). So, this register
// can be safely written without reading it first.
//
// Helper class `PipeScalerCoefficients` can be used to read from / write to
// the whole coefficient array.
//
// This register is available in Tiger Lake only.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev 2.0 Part 2, Pages 992-994
class PipeScalerCoefficientData : public hwreg::RegisterBase<PipeScalerCoefficientData, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x6819C;
// Stores the second coefficient stored in this register.
//
// The value is stored in PipeScalerCoefficientFormat format.
// Helper methods GetCoefficient2() and SetCoefficient2() can be used to get
// set the value of this field.
DEF_FIELD(31, 16, coefficient2_raw);
// Helper method to get value of the second coefficient.
PipeScalerCoefficientFormat coefficient2() const {
return PipeScalerCoefficientFormat().set_reg_value(coefficient2_raw());
}
// Helper method to set value of the second coefficient.
PipeScalerCoefficientData& set_coefficient2(const PipeScalerCoefficientFormat& coefficient) {
return set_coefficient2_raw(coefficient.reg_value());
}
// Stores the first coefficient stored in this register.
//
// The value is stored in PipeScalerCoefficientFormat format.
// Helper methods GetCoefficient1() and SetCoefficient1() can be used to get
// set the value of this field.
DEF_FIELD(15, 0, coefficient1_raw);
// Helper method to get value of the first coefficient.
PipeScalerCoefficientFormat coefficient1() const {
return PipeScalerCoefficientFormat().set_reg_value(coefficient1_raw());
}
// Helper method to set value of the first coefficient.
PipeScalerCoefficientData& set_coefficient1(const PipeScalerCoefficientFormat& coefficient) {
return set_coefficient1_raw(coefficient.reg_value());
}
};
// PS_COEF_INDEX (Pipe Scaler Programmable Coefficient Index)
//
// See PipeScalerCoefficientData class for the representation of scaler
// coefficients.
//
// This register is used together with PipeScalerCoefficientData to read / write
// the value of the coefficients. Before writing to the data register, software
// must set the initial index value (and optionally enable auto-increment)
// first.
//
// The coefficient data arrays are double buffered. Writing to the index / data
// register will update the buffered value, and writing to
// `PipeScalerWindowSize` will trigger the double buffering arm so that the
// buffered values will be applied at the start of the next vertical blank.
//
// This register's reserved fields are all MBZ (must be zero). So, this register
// can be safely written without reading it first.
//
// Helper class `PipeScalerCoefficients` can be used to read from / write to
// the whole coefficient array.
//
// This register is available in Tiger Lake only.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev 2.0 Part 2, Pages 995-997
class PipeScalerCoefficientIndex
: public hwreg::RegisterBase<PipeScalerCoefficientIndex, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x68198;
DEF_RSVDZ_FIELD(31, 11);
// Enables auto increment feature of the index register. If it is enabled,
// the index value will automatically increment by 1 every time
// PipeScalerCoefficientData register is read or written.
DEF_BIT(10, index_auto_increment_enabled);
DEF_RSVDZ_FIELD(9, 6);
// The index value used to read / write data registers.
// The index value must be between [0, 59] (inclusive).
DEF_FIELD(5, 0, index_raw);
PipeScalerCoefficientIndex& set_index(int index) {
ZX_ASSERT_MSG(index >= 0 && index <= 59, "Invalid index (%d); index must be in range [0, 59]",
index);
return set_index_raw(index);
}
};
// Pipe Scaler Coefficients Helper
//
// A helper class that software can use to write PipeScalerCoefficientFormat
// values to the data register, or read the data register contents back as a
// vector.
//
// This helper class only updates the values to the buffered registers, and
// software must trigger the double buffer arm register (PipeScalerWindowSize)
// by themselves to apply the value update.
//
// TODO(https://fxbug.dev/42071700): Move this alongside with scaler management logic,
// as this is a layer above the register definitions.
class PipeScalerCoefficients {
public:
PipeScalerCoefficients(hwreg::RegisterAddr<PipeScalerCoefficientIndex> index_address,
hwreg::RegisterAddr<PipeScalerCoefficientData> data_address)
: index_address_(index_address), data_address_(data_address) {}
// Write values of `coefficients` to the coefficient array using index / data
// registers.
// The size of `coefficients` must be 17 * 7 = 119.
template <typename T>
void WriteToRegister(cpp20::span<const PipeScalerCoefficientFormat> coefficients, T* reg_io) {
ZX_ASSERT(coefficients.size() == kNumCoefficients);
auto index_reg = index_address_.FromValue(0);
index_reg.set_reg_value(0).set_index(0).set_index_auto_increment_enabled(true).WriteTo(reg_io);
for (size_t i = 0; i < kNumCoefficients; i += 2) {
auto data_reg = data_address_.FromValue(0);
data_reg.set_coefficient1(coefficients[i]);
if (i + 1 < kNumCoefficients) {
data_reg.set_coefficient2(coefficients[i + 1]);
}
data_reg.WriteTo(reg_io);
}
}
// Read values of the coefficient array using index / data registers.
// Returns a coefficient array of size 17 * 7 = 119.
template <typename T>
std::vector<PipeScalerCoefficientFormat> ReadFromRegister(T* reg_io) {
std::vector<PipeScalerCoefficientFormat> coefficients;
coefficients.reserve(kNumCoefficients);
auto index_reg = index_address_.FromValue(0);
index_reg.set_reg_value(0).set_index(0).set_index_auto_increment_enabled(true).WriteTo(reg_io);
for (size_t i = kNumCoefficients % 2; i < kNumCoefficients; i += 2) {
auto data_reg = data_address_.ReadFrom(reg_io);
coefficients.push_back(
PipeScalerCoefficientFormat().set_reg_value(data_reg.coefficient1_raw()));
coefficients.push_back(
PipeScalerCoefficientFormat().set_reg_value(data_reg.coefficient2_raw()));
}
if (kNumCoefficients % 2 == 1) {
auto data_reg = data_address_.ReadFrom(reg_io);
coefficients.push_back(
PipeScalerCoefficientFormat().set_reg_value(data_reg.coefficient1_raw()));
}
ZX_DEBUG_ASSERT(coefficients.size() == kNumCoefficients);
return coefficients;
}
private:
static constexpr int kNumCoefficients = 17 * 7;
hwreg::RegisterAddr<PipeScalerCoefficientIndex> index_address_;
hwreg::RegisterAddr<PipeScalerCoefficientData> data_address_;
};
// PS_HPHASE (Pipe Scaler Horizontal Phase)
//
// Programs the scaler's horizontal filtering initial phase.
//
// The phase sample position must be adjusted for YUV 420 to YUV 444 upscaling
// so that the chroma sample position lands in the right spot. Note that this
// should not be set for HDR planes where Pipe Scaler doesn't upscale the
// chroma.
//
// The initial phase within the -0.5 to 1.5 range is supported.
//
// The phases are programmed as follows in the following YUV upscaling
// scenarios:
//
// YUV 420 Chroma Siting
// Top Left: Horizontal Phase = 0.25
// Bottom Right (MPEG-1): Horizontal Phase = -0.25
// Bottom Center (MPEG-2): Horizontal Phase = 0
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev 2.0 Part 2, Pages 1006-1007
// Kaby Lake: IHD-OS-KBL-Vol 2c-1.17 Part 2, Pages 653-654
class PipeScalerHorizontalInitialPhase
: public hwreg::RegisterBase<PipeScalerHorizontalInitialPhase, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x68194;
// This specifies the integer part of the initial phase of the Y semiplane
// filter.
//
// y_initial_phase_int = int(initial_phase) if initial_phase >= 0
// = 0 if initial_phase < 0
//
// A helper method `SetYInitialPhase()` should be used to set the value of
// this field.
//
// This field is ignored for non-YUV420 pixel formats.
DEF_FIELD(31, 30, y_initial_phase_int);
// This specifies the most significant 13 bits of the fractional part of the
// initial phase of the Y semiplane filter.
//
// y_initial_phase_fraction
// = int(initial_phase - int(initial_phase)) * 2 ^ 13 if initial_phase >= 0
// = int((1 - abs(initial_phase)) * 2 ^ 13) if initial_phase < 0
//
// A helper method `SetYInitialPhase()` should be used to set the value of
// this field.
//
// This field is ignored for non-YUV420 pixel formats.
DEF_FIELD(29, 17, y_initial_phase_fraction);
// Specifies whether the initial trip of the Y semiplane horizontal filtering
// may occur.
//
// y_initial_phase_trip_enabled = true if initial_phase >= 0
// = false if initial_phase < 0
//
// A helper method `SetYInitialPhase()` should be used to set the value of
// this field.
//
// This field is ignored for non-YUV420 pixel formats.
DEF_BIT(16, y_initial_phase_trip_enabled);
// A helper method that sets the value of initial phases of the Y semiplane.
//
// `initial_phase` must be a finite float number between [-0.5, 1.5].
//
// Only the most significant 13 bits of the fractional part are used to set
// the bitfields, and the software should be aware of the possible precision
// loss.
PipeScalerHorizontalInitialPhase& SetYInitialPhase(float initial_phase) {
ZX_ASSERT(std::isfinite(initial_phase));
ZX_ASSERT(initial_phase <= 1.5);
ZX_ASSERT(initial_phase >= -0.5);
if (initial_phase > 0) {
int integer = static_cast<int>(floor(initial_phase));
int fraction = static_cast<int>((initial_phase - static_cast<float>(integer)) * (1 << 13));
return set_y_initial_phase_trip_enabled(true)
.set_y_initial_phase_int(integer)
.set_y_initial_phase_fraction(fraction);
}
if (initial_phase == 0) {
return set_y_initial_phase_trip_enabled(true)
.set_y_initial_phase_int(0)
.set_y_initial_phase_fraction(0);
}
ZX_DEBUG_ASSERT(initial_phase < 0);
uint32_t fraction = static_cast<uint32_t>((1 - fabs(initial_phase)) * (1 << 13));
return set_y_initial_phase_trip_enabled(false)
.set_y_initial_phase_int(0)
.set_y_initial_phase_fraction(fraction);
}
// This specifies the integer part of the initial phase of the UV semiplane
// (for YUV420) or RGB filter.
//
// uv_initial_phase_int = int(initial_phase) if initial_phase >= 0
// = 0 if initial_phase < 0
DEF_FIELD(15, 14, uv_initial_phase_int);
// This specifies the most significant 13 bits of the fractional part of the
// initial phase of the UV semiplane (for YUV420) or RGB filter.
//
// uv_initial_phase_fraction
// = int(initial_phase - int(initial_phase)) * 2 ^ 13 if initial_phase >= 0
// = int(1 - abs(initial_phase)) * 2 ^ 13 if initial_phase < 0
DEF_FIELD(13, 1, uv_initial_phase_fraction);
// Specifies whether the initial trip of the UV semiplane (for YUV420) or
// RGB horizontal filtering may occur.
//
// y_initial_phase_trip_enabled = true if initial_phase >= 0
// = false if initial_phase < 0
DEF_BIT(0, uv_initial_phase_trip_enabled);
// A helper method that sets the value of initial phases of the UV semiplane
// (for YUV420) or RGB.
//
// `initial_phase` must be a finite float number between [-0.5, 1.5].
//
// Only the most significant 13 bits of the fractional part are used to set
// the bitfields, and the software should be aware of the possible precision
// loss.
PipeScalerHorizontalInitialPhase& SetUvInitialPhase(float initial_phase) {
ZX_ASSERT(std::isfinite(initial_phase));
ZX_ASSERT(initial_phase <= 1.5);
ZX_ASSERT(initial_phase >= -0.5);
if (initial_phase > 0) {
int integer = static_cast<int>(floor(initial_phase));
int fraction = static_cast<int>((initial_phase - static_cast<float>(integer)) * (1 << 13));
return set_uv_initial_phase_trip_enabled(true)
.set_uv_initial_phase_int(integer)
.set_uv_initial_phase_fraction(fraction);
}
if (initial_phase == 0) {
return set_uv_initial_phase_trip_enabled(true)
.set_uv_initial_phase_int(0)
.set_uv_initial_phase_fraction(0);
}
ZX_DEBUG_ASSERT(initial_phase < 0);
uint32_t fraction = static_cast<uint32_t>((1 - fabs(initial_phase)) * (1 << 13));
return set_uv_initial_phase_trip_enabled(false)
.set_uv_initial_phase_int(0)
.set_uv_initial_phase_fraction(fraction);
}
};
// PS_VPHASE (Pipe Scaler Vertical Phase)
//
// Programs the scaler's vertical filtering initial phase.
//
// The phase sample position must be adjusted for YUV 420 to YUV 444 upscaling
// so that the chroma sample position lands in the right spot. Note that this
// should not be set for HDR planes where Pipe Scaler doesn't upscale the
// chroma.
//
// The initial phase within the -0.5 to 1.5 range is supported.
//
// The register only works in Progressive Fetch - Progressive Display (PF-PD)
// mode and will be ignored in Progressive Fetch - Interlaced Display (PF-ID)
// mode.
//
// The phases are programmed as follows in the following YUV upscaling
// scenarios:
//
// YUV 420 Chroma Siting
// Top Left: Vertical Phase = 0.25
// Bottom Right (MPEG-1): Vertical Phase = -0.25
// Bottom Center (MPEG-2): Vertical Phase = 0
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev 2.0 Part 2, Pages 1016-1018
// Kaby Lake: IHD-OS-KBL-Vol 2c-1.17 Part 2, Pages 659-661
class PipeScalerVerticalInitialPhase
: public hwreg::RegisterBase<PipeScalerVerticalInitialPhase, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x68188;
// This specifies the integer part of the initial phase of the Y semiplane
// filter.
//
// y_initial_phase_int = int(initial_phase) if initial_phase >= 0
// = 0 if initial_phase < 0
//
// A helper method `SetYInitialPhase()` should be used to set the value of
// this field.
//
// This field is ignored for non-YUV420 pixel formats.
DEF_FIELD(31, 30, y_initial_phase_int);
// This specifies the most significant 13 bits of the fractional part of the
// initial phase of the Y semiplane filter.
//
// y_initial_phase_fraction
// = int(initial_phase - int(initial_phase)) * 2 ^ 13 if initial_phase >= 0
// = int(1 - abs(initial_phase)) * 2 ^ 13 if initial_phase < 0
//
// A helper method `SetYInitialPhase()` should be used to set the value of
// this field.
//
// This field is ignored for non-YUV420 pixel formats.
DEF_FIELD(29, 17, y_initial_phase_fraction);
// Specifies whether the initial trip of the Y semiplane vertical filtering
// may occur.
//
// y_initial_phase_trip_enabled = true if initial_phase >= 0
// = false if initial_phase < 0
//
// A helper method `SetYInitialPhase()` should be used to set the value of
// this field.
//
// This field is ignored for non-YUV420 pixel formats.
DEF_BIT(16, y_initial_phase_trip_enabled);
// A helper method that sets the value of initial phases of the Y semiplane.
//
// `initial_phase` must be a finite float number between [-0.5, 1.5].
//
// Only the most significant 13 bits of the fractional part are used to set
// the bitfields, and the software should be aware of the possible precision
// loss.
PipeScalerVerticalInitialPhase& SetYInitialPhase(float initial_phase) {
ZX_ASSERT(std::isfinite(initial_phase));
ZX_ASSERT(initial_phase <= 1.5);
ZX_ASSERT(initial_phase >= -0.5);
if (initial_phase > 0) {
int integer = static_cast<int>(floor(initial_phase));
int fraction = static_cast<int>((initial_phase - static_cast<float>(integer)) * (1 << 13));
return set_y_initial_phase_trip_enabled(true)
.set_y_initial_phase_int(integer)
.set_y_initial_phase_fraction(fraction);
}
if (initial_phase == 0) {
return set_y_initial_phase_trip_enabled(true)
.set_y_initial_phase_int(0)
.set_y_initial_phase_fraction(0);
}
ZX_DEBUG_ASSERT(initial_phase < 0);
uint32_t fraction = static_cast<uint32_t>((1 - fabs(initial_phase)) * (1 << 13));
return set_y_initial_phase_trip_enabled(false)
.set_y_initial_phase_int(0)
.set_y_initial_phase_fraction(fraction);
}
// This specifies the integer part of the initial phase of the UV semiplane
// (for YUV420) or RGB filter.
//
// uv_initial_phase_int = int(initial_phase) if initial_phase >= 0
// = 0 if initial_phase < 0
DEF_FIELD(15, 14, uv_initial_phase_int);
// This specifies the most significant 13 bits of the fractional part of the
// initial phase of the UV semiplane (for YUV420) or RGB filter.
//
// uv_initial_phase_fraction
// = int(initial_phase - int(initial_phase)) * 2 ^ 13 if initial_phase >= 0
// = int(1 - fabs(initial_phase)) * 2 ^ 13 if initial_phase < 0
DEF_FIELD(13, 1, uv_initial_phase_fraction);
// Specifies whether the initial trip of the UV semiplane (for YUV420) or
// RGB vertical filter may occur.
//
// y_initial_phase_trip_enabled = true if initial_phase >= 0
// = false if initial_phase < 0
DEF_BIT(0, uv_initial_phase_trip_enabled);
// A helper method that sets the value of initial phases of the UV semiplane
// (for YUV420) or RGB.
//
// `initial_phase` must be a finite float number between [-0.5, 1.5].
//
// Only the most significant 13 bits of the fractional part are used to set
// the bitfields, and the software should be aware of the possible precision
// loss.
PipeScalerVerticalInitialPhase& SetUvInitialPhase(float initial_phase) {
ZX_ASSERT(std::isfinite(initial_phase));
ZX_ASSERT(initial_phase <= 1.5);
ZX_ASSERT(initial_phase >= -0.5);
if (initial_phase > 0) {
int integer = static_cast<int>(floor(initial_phase));
int fraction = static_cast<int>((initial_phase - static_cast<float>(integer)) * (1 << 13));
return set_uv_initial_phase_trip_enabled(true)
.set_uv_initial_phase_int(integer)
.set_uv_initial_phase_fraction(fraction);
}
if (initial_phase == 0) {
return set_uv_initial_phase_trip_enabled(true)
.set_uv_initial_phase_int(0)
.set_uv_initial_phase_fraction(0);
}
ZX_DEBUG_ASSERT(initial_phase < 0);
uint32_t fraction = static_cast<uint32_t>((1 - fabs(initial_phase)) * (1 << 13));
return set_uv_initial_phase_trip_enabled(false)
.set_uv_initial_phase_int(0)
.set_uv_initial_phase_fraction(fraction);
}
};
// PS_PWR_GATE (Pipe Scaler Power Gate Control)
//
// Controls the power gate for pipe scaler memory.
//
// This register is double buffered. See PipeScalerWindowSize for arming and
// dis-arming double-buffer updates.
//
// 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-Rev 2.0, Page 1014-1015
// Kaby Lake: IHD-OS-KBL-Vol 2c-1.17 Part 2, Pages 657-658
class PipeScalerPowerGateControl
: public hwreg::RegisterBase<PipeScalerPowerGateControl, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x68160;
DEF_RSVDZ_FIELD(30, 6);
// Disables the dynamic power gate of unused memory embedded blocks (EBB)
// when processing low resolution source images.
//
// This bit is only available on Tiger Lake. On Kaby Lake and Skylake,
// this bit must be zero.
DEF_BIT(5, dynamic_power_gate_disabled_tiger_lake);
// Time for RAMs in a given filter group to settle after they are powered up.
enum class FilterGroupRamSettlingTime : uint32_t {
k32CoreDisplayClockPeriods = 0b00,
k64CoreDisplayClockPeriods = 0b01,
k96CoreDisplayClockPeriods = 0b10,
k128CoreDisplayClockPeriods = 0b11,
};
// This field is only available on Kaby Lake and Skylake. On Tiger Lake, this
// field is reserved.
DEF_ENUM_FIELD(FilterGroupRamSettlingTime, 4, 3, filter_group_ram_settling_time_skylake);
// Delay between sleep enables of individual banks of RAMs.
enum class SleepEnableDelayTime : uint32_t {
k8CoreDisplayClockPeriods = 0b00,
k16CoreDisplayClockPeriods = 0b01,
k24CoreDisplayClockPeriods = 0b10,
k32CoreDisplayClockPeriods = 0b11,
};
// This field is only available on Kaby Lake and Skylake. On Tiger Lake, this
// field is reserved.
DEF_ENUM_FIELD(SleepEnableDelayTime, 1, 0, sleep_enable_delay_time_skylake);
};
// PS_HSCALE / PS_VSCALE (Pipe Scaler Horizontal / Vertical Scaling Factor)
//
// The pipe / plane scaling factor. The register uses a fixed-point
// representation to store the value, which can be converted to C float type
// by using helper method ToFloat().
//
// If the pipe / transcoder works in progressive display mode (PF-PD),
// Horizontal scaling factor = Source width / Destination width
// Vertical scaling factor = Source height / Destination height.
//
// If the pipe / transcoder works in interlaced display mode (PF-ID),
// Horizontal scaling factor = 2 * Source width / Destination width
// Vertical scaling factor = 2 * Source height / Destination height.
//
// This register is read only.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev 2.0 Part 2, Pages 1008-1009, 1019-1020
// Kaby Lake: IHD-OS-KBL-Vol 2c-1.17 Part 2, Pages 655-656, 662-663
// Skylake: IHD-OS-SKL-Vol 2c-05.16 Part 2, Pages 648-649, 655-656
class PipeScalerScalingFactor : public hwreg::RegisterBase<PipeScalerScalingFactor, uint32_t> {
public:
static constexpr uint32_t kHorizontalBaseAddr = 0x68190;
static constexpr uint32_t kVerticalBaseAddr = 0x68184;
DEF_FIELD(17, 15, integer_part);
static constexpr uint32_t kIntegerPartSize = 3;
DEF_FIELD(14, 0, fraction_part);
static constexpr uint32_t kFractionPartSize = 15;
// Converts the scaling factor to float format.
//
// The scaling factor is stored as an unsigned fixed point format with 3
// integer bits and 15 fractional bits.
//
// On platforms using IEEE 754 standard, all the valid values stored in this
// register can be converted to |float| without losing precision.
float ToFloat() const {
int x32768 = (static_cast<int>(integer_part()) << 15) + static_cast<int>(fraction_part());
return static_cast<float>(x32768) / 32768.0f;
}
};
// PS_WIN_SZ (Pipe Scaler Window Size)
//
// The scaler outputs the scaled contents to the scaler window, a rectangular
// region specified by `PipeScalerWindowPosition` and `PipeScalerWindowSize`
// on the output surface.
//
// This register specifies the size of the scaler window. "x" and "y" are
// relative to the display device, thus rotation / flipping of planes and pipe
// doesn't affect the order of x and y.
//
// This register and `PipeScalerWindowPosition` must be set so that the whole
// scaler window is within the output surface; see documentation of
// `PipeScalerWindowPosition` for the details of the constraints.
//
// This register is double buffered. Writing to this register will trigger
// double buffering arms to this register and all the other Pipe Scaler control
// registers so that they are updated at the start of the next vertical blank.
// So this register must be written at the end of all the pipe scaler
// configuration procedures.
//
// This register's reserved fields are all MBZ (must be zero). So, this register
// can be safely written without reading it first.
//
// Tiger Lake: IHD-OS-TGL-Vol 2c-1.22-Rev 2.0 Part 2, Pages 1023-1024
// Kaby Lake: IHD-OS-KBL-Vol 2c-1.17 Part 2, Pages 664-665
class PipeScalerWindowSize : public hwreg::RegisterBase<PipeScalerWindowSize, uint32_t> {
public:
static constexpr uint32_t kBaseAddr = 0x68174;
DEF_RSVDZ_FIELD(31, 29);
// Horizontal (x) size of the rectangular area.
//
// Must not exceed 5120 for unjoined pipes and 7680 / #(joined pipes) for
// joined pipes.
// Must be even for planar YUV planes / pipes.
DEF_FIELD(28, 16, x_size);
DEF_RSVDZ_FIELD(15, 13);
// Vertical (y) size of the rectangular area.
//
// Must not exceed 4096 for unjoined pipes and 4320 for joined pipes.
// Must be even for planar YUV planes / pipes, or for interlaced output.
DEF_FIELD(12, 0, y_size);
};
// An instance of PipeScalerRegs represents the registers for a particular pipe
// scaler.
class PipeScalerRegs {
public:
explicit PipeScalerRegs(i915::PipeId pipe_id, int scaler_index)
: pipe_id_(pipe_id), scaler_index_(scaler_index) {}
hwreg::RegisterAddr<PipeScalerControlSkylake> PipeScalerControlSkylake() {
return hwreg::RegisterAddr<registers::PipeScalerControlSkylake>(
PipeScalerControlSkylake::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerControlTigerLake> PipeScalerControlTigerLake() {
return hwreg::RegisterAddr<registers::PipeScalerControlTigerLake>(
PipeScalerControlTigerLake::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerAdaptiveFilterThresholds> PipeScalerAdaptiveFilterThresholds() {
return hwreg::RegisterAddr<registers::PipeScalerAdaptiveFilterThresholds>(
PipeScalerAdaptiveFilterThresholds::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerCoefficientData> PipeScalerCoefficientData() {
return hwreg::RegisterAddr<registers::PipeScalerCoefficientData>(
PipeScalerCoefficientData::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerCoefficientIndex> PipeScalerCoefficientIndex() {
return hwreg::RegisterAddr<registers::PipeScalerCoefficientIndex>(
PipeScalerCoefficientIndex::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
PipeScalerCoefficients PipeScalerCoefficients() {
return registers::PipeScalerCoefficients(PipeScalerCoefficientIndex(),
PipeScalerCoefficientData());
}
hwreg::RegisterAddr<PipeScalerHorizontalInitialPhase> PipeScalerHorizontalInitialPhase() {
return hwreg::RegisterAddr<registers::PipeScalerHorizontalInitialPhase>(
PipeScalerHorizontalInitialPhase::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerVerticalInitialPhase> PipeScalerVerticalInitialPhase() {
return hwreg::RegisterAddr<registers::PipeScalerVerticalInitialPhase>(
PipeScalerVerticalInitialPhase::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerPowerGateControl> PipeScalerPowerGateControl() {
return hwreg::RegisterAddr<registers::PipeScalerPowerGateControl>(
PipeScalerPowerGateControl::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerScalingFactor> PipeScalerHorizontalScalingFactor() {
return hwreg::RegisterAddr<registers::PipeScalerScalingFactor>(
PipeScalerScalingFactor::kHorizontalBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerScalingFactor> PipeScalerVerticalScalingFactor() {
return hwreg::RegisterAddr<registers::PipeScalerScalingFactor>(
PipeScalerScalingFactor::kVerticalBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerWindowPosition> PipeScalerWindowPosition() {
return hwreg::RegisterAddr<registers::PipeScalerWindowPosition>(
PipeScalerWindowPosition::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
hwreg::RegisterAddr<PipeScalerWindowSize> PipeScalerWindowSize() {
return hwreg::RegisterAddr<registers::PipeScalerWindowSize>(
PipeScalerWindowSize::kBaseAddr + 0x800 * pipe_id_ + scaler_index_ * 0x100);
}
private:
i915::PipeId pipe_id_;
int scaler_index_;
};
} // namespace registers
#endif // SRC_GRAPHICS_DISPLAY_DRIVERS_INTEL_I915_REGISTERS_PIPE_SCALER_H_