blob: dda04dd49225fb1d57c51e209131ab7d5c019598 [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_AMLOGIC_DISPLAY_VIDEO_INPUT_REGS_H_
#define SRC_GRAPHICS_DISPLAY_DRIVERS_AMLOGIC_DISPLAY_VIDEO_INPUT_REGS_H_
#include <zircon/assert.h>
#include <cstdint>
#include <hwreg/bitfields.h>
#include "src/graphics/display/lib/driver-framework-migration-utils/logging/zxlogf.h"
namespace amlogic_display {
// There are two video input modules (VDIN) in Amlogic display engine that
// receive video from external input (e.g. BT.656) or internal input (e.g.
// internal VIU loopback), and write the data back to the DDR memory.
enum class VideoInputModuleId {
kVideoInputModule0 = 0,
kVideoInputModule1 = 1,
};
// VDIN0_COM_CTRL0, VDIN1_COM_CTRL0.
//
// A311D Datasheet, Section 10.2.3.42 VDIN, Pages 1086-1087, 1108-1109.
// S905D2 Datasheet, Section 7.2.3.41 VDIN, Pages 777, 801.
// S905D3 Datasheet, Section 8.2.3.42 VDIN, Pages 713-714, 736-737.
class VideoInputCommandControl : public hwreg::RegisterBase<VideoInputCommandControl, uint32_t> {
public:
enum class ComponentInput : uint32_t {
kComponentInput0 = 0b00,
kComponentInput1 = 0b01,
kComponentInput2 = 0b10,
};
// Values for the `input_source_selection` field.
enum class InputSource : uint32_t {
kNoInput = 0,
kMpegFromDram = 1,
kBt656 = 2,
kReservedForComponent = 3,
kReservedForTvDecoder = 4,
kReservedForHdmiRx = 5,
kDigitalVideoInput = 6,
// Source selected by `WritebackMuxControl`.
//
// This source is documented as "Internal loopback from VIU" on A311D,
// S905D2, and T931. Experiments on VIM3 (A311D), Astro (S905D2) and
// Sherlock (T931) confirmed that the behavior actually matches S905D3.
kWritebackMux0 = 7,
kReservedForMipiCsi2 = 8,
// Source selected by `WritebackMuxControl`.
//
// This source is documented as "Reserved (ISP)" on A311D, S905D2, and T931.
// Experiments on VIM3 (A311D), Astro (S905D2) and Sherlock (T931) confirmed
// that the behavior actually matches S905D3.
kWritebackMux1 = 9,
kSecondBt656 = 10,
};
static hwreg::RegisterAddr<VideoInputCommandControl> Get(VideoInputModuleId video_input) {
switch (video_input) {
case VideoInputModuleId::kVideoInputModule0:
return {0x1202 * sizeof(uint32_t)};
case VideoInputModuleId::kVideoInputModule1:
return {0x1302 * sizeof(uint32_t)};
}
ZX_DEBUG_ASSERT_MSG(false, "Invalid video input module ID: %d", static_cast<int>(video_input));
}
DEF_BIT(31, bypass_mpeg_noise_reduction);
DEF_BIT(30, mpeg_field_info);
// Trigger a go_field (Vsync) pulse on the video input module when true is
// written.
DEF_BIT(29, trigger_go_field_pulse);
// Trigger a go_line (Hsync) pulse on the video input module when true is
// written.
DEF_BIT(28, trigger_go_line_pulse);
DEF_BIT(27, mpeg_go_field_input_signal_enabled);
// Not documented for this register; for fields of the same name in other
// registers (VD1_IF0_GEN_REG, DI_IF0_GEN_REG, etc.), `hold_lines` is the
// number of lines to hold after go_field pulse and before the module is
// enabled.
DEF_FIELD(26, 20, hold_lines);
// Whether the `go_field` pulse is delayed for the video input module.
DEF_BIT(19, go_field_pulse_delayed);
// Number of lines that `go_field` pulse is delayed, if
// `go_field_pulse_delayed` is true.
DEF_FIELD(18, 12, go_field_pulse_delay_lines);
// Seems unused for internal loopback mode.
DEF_ENUM_FIELD(ComponentInput, 11, 10, component2_output_selection);
DEF_ENUM_FIELD(ComponentInput, 9, 8, component1_output_selection);
DEF_ENUM_FIELD(ComponentInput, 7, 6, component0_output_selection);
// Indicates whether the video input is cropped using a window specified by
// `VDIN0/1_WIN_H_START_END` and `VDIN0/1_WIN_V_START_END` registers.
DEF_BIT(5, video_input_cropped);
DEF_BIT(4, video_input_enabled);
// If the input source doesn't equal to any value specified in `InputSource`,
// no input is provided to the video input module.
DEF_ENUM_FIELD(InputSource, 3, 0, input_source_selection);
VideoInputCommandControl& SetInputSource(InputSource input_source) {
switch (input_source) {
case InputSource::kNoInput:
case InputSource::kMpegFromDram:
case InputSource::kBt656:
case InputSource::kReservedForComponent:
case InputSource::kReservedForTvDecoder:
case InputSource::kReservedForHdmiRx:
case InputSource::kDigitalVideoInput:
case InputSource::kWritebackMux0:
case InputSource::kReservedForMipiCsi2:
case InputSource::kWritebackMux1:
case InputSource::kSecondBt656:
return set_input_source_selection(input_source);
}
ZX_DEBUG_ASSERT_MSG(false, "Unsupported input source: %" PRIu32,
static_cast<uint32_t>(input_source));
return set_input_source_selection(InputSource::kNoInput);
}
InputSource GetInputSource() const {
InputSource input_source = input_source_selection();
switch (input_source) {
case InputSource::kNoInput:
case InputSource::kMpegFromDram:
case InputSource::kBt656:
case InputSource::kReservedForComponent:
case InputSource::kReservedForTvDecoder:
case InputSource::kReservedForHdmiRx:
case InputSource::kDigitalVideoInput:
case InputSource::kWritebackMux0:
case InputSource::kReservedForMipiCsi2:
case InputSource::kWritebackMux1:
case InputSource::kSecondBt656:
return input_source;
}
return InputSource::kNoInput;
}
};
// VDIN0_COM_STATUS0, VDIN1_COM_STATUS0
//
// This register is read-only.
//
// A311D Datasheet, Section 10.2.3.42 VDIN, Pages 1087, 1109
// S905D2 Datasheet, Section 7.2.3.41 VDIN, Pages 778, 802
// S905D3 Datasheet, Section 8.2.3.41 VDIN, Pages 714, 737
class VideoInputCommandStatus0 : public hwreg::RegisterBase<VideoInputCommandStatus0, uint32_t> {
public:
static hwreg::RegisterAddr<VideoInputCommandStatus0> Get(VideoInputModuleId video_input) {
switch (video_input) {
case VideoInputModuleId::kVideoInputModule0:
return {0x1205 * sizeof(uint32_t)};
case VideoInputModuleId::kVideoInputModule1:
return {0x1305 * sizeof(uint32_t)};
}
ZX_DEBUG_ASSERT_MSG(false, "Invalid video input module ID: %d", static_cast<int>(video_input));
}
// Bits 17-3` are defined differently for VDIN0_COM_STATUS0 and
// VDIN0_COM_STATUS0, in all the datasheets mentioned above.
//
// VDIN0_COM_STATUS0 uses bit 17 as `vid_wr_pending_ddr_wrrsp`, bit 16
// as `curr_pic_sec`, and bit 15 as `curr_pic_sec_sav`, bits 14-3 as
// `lfifo_buf_cnt`.
//
// VDIN1_COM_STATUS0 uses bits 12-3 as `lfifo_buf_cnt` and bits 17-13
// reserved.
//
// Since these fields are not currently used by the driver, we are omitting
// these fields as reserved. Future drivers may need to fork the register
// definitions or create helper functions to access the fields.
// Indicates that the write of raw pixels from input source to RAM is done.
//
// Cleared by `clear_direct_write_done` bit in `VDIN0/1_WR_CTRL` register.
DEF_BIT(2, direct_write_done);
// Indicates that the write of noise-reduced (NR) pixels from input source to
// RAM is done.
//
// Cleared by `clear_noise_reduced_write_done` bit in `VDIN0/1_WR_CTRL`
// register.
DEF_BIT(1, noise_reduced_write_done);
// Current field for interlaced input.
//
// For interlaced inputs, 0 means top field, 1 means bottom field.
// This is not documented in Amlogic datasheets but appears in drivers.
//
// Unused for progressive inputs.
DEF_BIT(0, current_field);
};
// There are multiple video input channels (VDIs, possibly shorthand for Video
// Data Input) available for video input modules (VDINs), numbered from VDI1 to
// VDI9. Each VDIN has one asynchronous FIFO (ASFIFO) for each VDI to receive
// pixels from.
//
// For each VDIN, there are four control registers (ASFIFO_CTRL0/1/2/3) to
// configure the way the VDIN reads pixels from a channel by setting the
// corresponding FIFO behaviors. The layout of the ASFIFO configuration fields
// is the same across all channels.
//
// Currently this driver only uses VDI 6 and VDI 8; control fields / registers
// for all the other VDI channels are not defined here.
//
// A311D Datasheet, Section 10.2.3.42 VDIN, Pages 1088-1090, 1106, 1110-1112,
// 1128.
// S905D2 Datasheet, Section 7.2.3.41 VDIN, Pages 779-781, 798-799, 802-805,
// 822.
// S905D3 Datasheet, Section 8.2.3.42 VDIN, Pages 715-717, 733, 738-740, 755.
// VDIN0_ASFIFO_CTRL2, VDIN1_ASFIFO_CTRL2
//
// A311D Datasheet, Section 10.2.3.42 VDIN, Pages 1090, 1112.
// S905D2 Datasheet, Section 7.2.3.41 VDIN, Pages 781, 805.
// S905D3 Datasheet, Section 8.2.3.42 VDIN, Pages 717, 740.
class VideoInputChannelFifoControl2
: public hwreg::RegisterBase<VideoInputChannelFifoControl2, uint32_t> {
public:
static hwreg::RegisterAddr<VideoInputChannelFifoControl2> Get(VideoInputModuleId video_input) {
switch (video_input) {
case VideoInputModuleId::kVideoInputModule0:
return {0x120f * sizeof(uint32_t)};
case VideoInputModuleId::kVideoInputModule1:
return {0x130f * sizeof(uint32_t)};
}
ZX_DEBUG_ASSERT_MSG(false, "Invalid video input module ID: %d", static_cast<int>(video_input));
}
// Bits 25 and 23-20 provide additional configuration on decimation.
// These bits are not defined because this driver currently does not support
// decimation.
// True iff input decimation subsampling is enabled.
DEF_BIT(24, decimation_data_enabled);
// Only 1 / (decimation_ratio_minus_1 + 1) of the pixels will be sampled.
// Setting this field to zero effectively disables decimation.
DEF_FIELD(19, 16, decimation_ratio_minus_1);
// Bits 7-0 configure VDI 5. These bits are not defined because this driver
// currently does not support decimation.
};
// VDIN0_ASFIFO_CTRL3, VDIN1_ASFIFO_CTRL3
//
// A311D Datasheet, Section 10.2.3.42 VDIN, Pages 1106, 1128.
// S905D2 Datasheet, Section 7.2.3.41 VDIN, Pages 798-799, 822.
// S905D3 Datasheet, Section 8.2.3.42 VDIN, Pages 733, 755.
class VideoInputChannelFifoControl3
: public hwreg::RegisterBase<VideoInputChannelFifoControl3, uint32_t> {
public:
static hwreg::RegisterAddr<VideoInputChannelFifoControl3> Get(VideoInputModuleId video_input) {
switch (video_input) {
case VideoInputModuleId::kVideoInputModule0:
return {0x126f * sizeof(uint32_t)};
case VideoInputModuleId::kVideoInputModule1:
return {0x136f * sizeof(uint32_t)};
}
ZX_DEBUG_ASSERT_MSG(false, "Invalid video input module ID: %d", static_cast<int>(video_input));
}
// Bits 31-24 configure VDI 9.
// Currently this driver doesn't use VDI channel 9, so we don't define these
// bits.
// Bits 23-16 configure VDI 8. These bits are not documented in any
// datasheet. Experiments on a VIM3 (using Amlogic A311D) show that these
// bits correspond to VDI 8 / ASFIFO 8.
// Enable data transmission on channel 8.
DEF_BIT(23, channel8_data_enabled);
// Enable go_field (Vsync) signals on channel 8.
DEF_BIT(22, channel8_go_field_signal_enabled);
// Enable go_line (Hsync) signals for channel 8.
DEF_BIT(21, channel8_go_line_signal_enabled);
// True iff the input video on channel 8 has negative polarity Vsync signals.
DEF_BIT(20, channel8_input_vsync_is_negative);
// True iff the input video on channel 6 has negative polarity Hsync signals.
DEF_BIT(19, channel8_input_hsync_is_negative);
// If true, the ASFIFO will be reset on each Vsync signal.
DEF_BIT(18, channel8_async_fifo_software_reset_on_vsync);
// Clears (and acknowledges) the `vdi8_fifo_overflow` bit in the
// `VDIN0/1_COM_STATUS2` register.
DEF_BIT(17, channel8_clear_fifo_overflow_bit);
// Resets the async FIFO.
//
// This bit is a "level signal" bit. Drivers reset the FIFO by first setting
// it to 1, and then to 0.
DEF_BIT(16, channel8_async_fifo_software_reset);
// Bits 15-9 configure VDI 7.
// Currently this driver doesn't use VDI channel 7, so we don't define these
// bits.
// Enable data transmission on channel 6.
DEF_BIT(7, channel6_data_enabled);
// Enable go_field (Vsync) signals on channel 6.
DEF_BIT(6, channel6_go_field_signal_enabled);
// Enable go_line (Hsync) signals on channel 6.
DEF_BIT(5, channel6_go_line_signal_enabled);
// True iff the input video on channel 6 has negative polarity Vsync signals.
DEF_BIT(4, channel6_input_vsync_is_negative);
// True iff the input video on channel 6 has negative polarity Hsync signals.
DEF_BIT(3, channel6_input_hsync_is_negative);
// If true, the channel ASFIFO will be reset on each Vsync signal.
DEF_BIT(2, channel6_async_fifo_software_reset_on_vsync);
// Clears (and acknowledges) the `vdi6_fifo_overflow` bit in the
// `VDIN0/1_COM_STATUS2` register.
DEF_BIT(1, channel6_clear_fifo_overflow_bit);
// Resets the async FIFO.
//
// This bit is a "level signal" bit. Drivers reset the FIFO by first setting
// it to 1, and then to 0.
DEF_BIT(0, channel6_async_fifo_software_reset);
};
// Selects the clock or data source for a writeback mux.
//
// Fields of this type must transition through `kDisabled` when being updated.
enum class WritebackMuxSource : uint32_t {
// Disable the input path. A required intermediate step for changing input
// sources.
kDisabled = 0b00000,
// VIU ENCI domain.
kEncoderInterlaced = 0b00001,
// VIU ENCP domain.
kEncoderProgressive = 0b00010,
// VIU ENCT domain.
kEncoderTvPanel = 0b00100,
// Also known as "VIU writeback domain 1" in S905D3 datasheets.
kViuWriteback0 = 0b01000,
// Also known as "VIU writeback domain 2" in S905D3 datasheets.
kViuWriteback1 = 0b10000,
};
// VPU_VIU_VDIN_IF_MUX_CTRL
//
// Each VDIN (Video Input Module) can receive image data from one of the data
// sources available on the SoC, selected via the `VideoInputCommandControl`
// register. Two of the data sources, `kWritebackMux0` and `kWritebackMux1`,
// are actually multiplexers connected to multiple sources.
//
// This register configures the multiplexers. Each multiplexer has clock and
// data outputs ("paths" in the datasheets), which are configured separately.
//
// Many configurations are invalid. For example, a multiplexer's clock and data
// outputs must be connected to the same source. To reduce the likelihood of
// errors, this register's fields should be accessed exclusively via the
// higher-level helper methods defined after the fields.
//
// S905D3 Datasheet, Section 8.2.3.1 "VPU Registers", Page 314.
//
// This register is not documented in the datasheets for S905D2, A311D and T931.
// However, experiments on VIM3 (Amlogic A311D), Astro (Amlogic S905D2) and
// Sherlock (Amlogic T931) show that the register exists and has the same layout
// and functionality as that in S905D3.
class WritebackMuxControl : public hwreg::RegisterBase<WritebackMuxControl, uint32_t> {
public:
static hwreg::RegisterAddr<WritebackMuxControl> Get() { return {0x2783 * sizeof(uint32_t)}; }
// Selects the data path from VIU/Encoder to writeback mux 1.
//
// This field is effective when a `VideoInputCommandControl` register selects
// the `kWritebackMux1` input ("VDIN0/1 source input 9" in the datasheet).
//
// It's preferred to use `GetMux1Selection()` and `SetMux1Selection()` helper
// functions to change the data path. For direct register manipulations,
// `mux1_data_selection` and `mux1_clock_selection` must be equal, otherwise
// the behavior is undefined.
DEF_ENUM_FIELD(WritebackMuxSource, 28, 24, mux1_data_selection);
// Selects the clock path from VIU/Encoder to writeback mux 1.
//
// This field is effective when a `VideoInputCommandControl` register selects
// the `kWritebackMux1` input ("VDIN0/1 source input 9" in the datasheet).
//
// It's preferred to use `GetMux1Selection()` and `SetMux1Selection()` helper
// functions to change the data path. For direct register manipulations,
// `mux1_data_selection` and `mux1_clock_selection` must be equal, otherwise
// the behavior is undefined.
DEF_ENUM_FIELD(WritebackMuxSource, 20, 16, mux1_clock_selection);
// Selects the data path from VIU/Encoder to writeback mux 0.
//
// This field is effective when a `VideoInputCommandControl` register selects
// the `kWritebackMux0` input ("VDIN0/1 source input 7" in the datasheet).
//
// It's preferred to use `GetMux0Selection()` and `SetMux0Selection()` helper
// functions to change the data path. For direct register manipulations,
// `mux0_data_selection` and `mux0_clock_selection` must be equal, otherwise
// the behavior is undefined.
DEF_ENUM_FIELD(WritebackMuxSource, 12, 8, mux0_data_selection);
// Selects the clock path from VIU/Encoder to writeback mux 0.
//
// This field is effective when a `VideoInputCommandControl` register selects
// the `kWritebackMux0` input ("VDIN0/1 source input 7" in the datasheet).
//
// It's preferred to use `GetMux0Selection()` and `SetMux0Selection()` helper
// functions to change the data path. For direct register manipulations,
// `mux0_data_selection` and `mux0_clock_selection` must be equal, otherwise
// the behavior is WritebackMuxSelection.
DEF_ENUM_FIELD(WritebackMuxSource, 4, 0, mux0_clock_selection);
// The clock/data source selected for writeback mux 1.
WritebackMuxSource GetMux1Selection() const {
WritebackMuxSource clock = mux1_clock_selection();
WritebackMuxSource data = mux1_data_selection();
if (clock != data) {
zxlogf(WARNING, "Writeback mux1 clock selection %" PRIu32 " != data selection %" PRIu32,
static_cast<uint32_t>(clock), static_cast<uint32_t>(data));
}
return clock;
}
// Set the data/clock source for writeback mux 1.
WritebackMuxControl& SetMux1Selection(WritebackMuxSource mux_selection) {
ZX_ASSERT(GetMux1Selection() == WritebackMuxSource::kDisabled ||
mux_selection == WritebackMuxSource::kDisabled);
switch (mux_selection) {
case WritebackMuxSource::kDisabled:
case WritebackMuxSource::kEncoderInterlaced:
case WritebackMuxSource::kEncoderProgressive:
case WritebackMuxSource::kEncoderTvPanel:
case WritebackMuxSource::kViuWriteback0:
case WritebackMuxSource::kViuWriteback1:
set_mux1_clock_selection(mux_selection);
set_mux1_data_selection(mux_selection);
return *this;
}
ZX_DEBUG_ASSERT_MSG(false, "Invalid mux selection %" PRIu32,
static_cast<uint32_t>(mux_selection));
return *this;
}
// The clock/data source selected for writeback mux 0.
WritebackMuxSource GetMux0Selection() const {
WritebackMuxSource clock = mux0_clock_selection();
WritebackMuxSource data = mux0_data_selection();
if (clock != data) {
zxlogf(WARNING, "Writeback mux0 clock selection %" PRIu32 " != data selection %" PRIu32,
static_cast<uint32_t>(clock), static_cast<uint32_t>(data));
}
return clock;
}
// Set the data/clock source for writeback mux 0.
WritebackMuxControl& SetMux0Selection(WritebackMuxSource mux_selection) {
ZX_ASSERT(GetMux0Selection() == WritebackMuxSource::kDisabled ||
mux_selection == WritebackMuxSource::kDisabled);
switch (mux_selection) {
case WritebackMuxSource::kDisabled:
case WritebackMuxSource::kEncoderInterlaced:
case WritebackMuxSource::kEncoderProgressive:
case WritebackMuxSource::kEncoderTvPanel:
case WritebackMuxSource::kViuWriteback0:
case WritebackMuxSource::kViuWriteback1:
set_mux0_clock_selection(mux_selection);
set_mux0_data_selection(mux_selection);
return *this;
}
ZX_DEBUG_ASSERT_MSG(false, "Invalid mux selection %" PRIu32,
static_cast<uint32_t>(mux_selection));
return *this;
}
};
} // namespace amlogic_display
#endif // SRC_GRAPHICS_DISPLAY_DRIVERS_AMLOGIC_DISPLAY_VIDEO_INPUT_REGS_H_