| // Copyright 2018 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. |
| |
| #include "src/graphics/display/drivers/amlogic-display/osd.h" |
| |
| #include <fuchsia/hardware/display/controller/c/banjo.h> |
| #include <lib/ddk/debug.h> |
| #include <lib/zx/clock.h> |
| #include <lib/zx/pmt.h> |
| #include <lib/zx/time.h> |
| #include <lib/zx/vmar.h> |
| #include <threads.h> |
| #include <zircon/assert.h> |
| #include <zircon/errors.h> |
| #include <zircon/syscalls.h> |
| #include <zircon/types.h> |
| #include <zircon/utc.h> |
| |
| #include <algorithm> |
| #include <cfloat> |
| #include <cmath> |
| #include <cstdint> |
| |
| #include <ddktl/device.h> |
| #include <fbl/algorithm.h> |
| #include <fbl/auto_lock.h> |
| |
| #include "src/graphics/display/drivers/amlogic-display/amlogic-display.h" |
| #include "src/graphics/display/drivers/amlogic-display/common.h" |
| #include "src/graphics/display/drivers/amlogic-display/hhi-regs.h" |
| #include "src/graphics/display/drivers/amlogic-display/rdma-regs.h" |
| #include "src/graphics/display/drivers/amlogic-display/vpp-regs.h" |
| #include "src/graphics/display/drivers/amlogic-display/vpu-regs.h" |
| #include "src/graphics/display/lib/api-types-cpp/config-stamp.h" |
| |
| namespace amlogic_display { |
| |
| #define READ32_VPU_REG(a) vpu_mmio_->Read32(a) |
| #define WRITE32_VPU_REG(a, v) vpu_mmio_->Write32(v, a) |
| |
| namespace { |
| constexpr uint32_t kMaximumAlpha = 0xff; |
| |
| // We use bicubic interpolation for scaling. |
| // TODO(payamm): Add support for other types of interpolation |
| unsigned int osd_filter_coefs_bicubic[] = { |
| 0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300, 0xfd7e0500, 0xfc7e0600, 0xfb7d0800, |
| 0xfb7c0900, 0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff, 0xf87613ff, 0xf87416fe, |
| 0xf87218fe, 0xf8701afe, 0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd, 0xf76627fc, |
| 0xf76429fc, 0xf7612cfc, 0xf75f2ffb, 0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa, |
| 0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9, 0xf84848f8}; |
| |
| constexpr uint32_t kFloatToFixed3_10ScaleFactor = 1024; |
| constexpr int32_t kMaxFloatToFixed3_10 = (4 * kFloatToFixed3_10ScaleFactor) - 1; |
| constexpr int32_t kMinFloatToFixed3_10 = -4 * kFloatToFixed3_10ScaleFactor; |
| constexpr uint32_t kFloatToFixed3_10Mask = 0x1FFF; |
| |
| constexpr uint32_t kFloatToFixed2_10ScaleFactor = 1024; |
| constexpr int32_t kMaxFloatToFixed2_10 = (2 * kFloatToFixed2_10ScaleFactor) - 1; |
| constexpr int32_t kMinFloatToFixed2_10 = -2 * kFloatToFixed2_10ScaleFactor; |
| constexpr uint32_t kFloatToFixed2_10Mask = 0xFFF; |
| |
| // AFBC related constants |
| constexpr uint32_t kAfbcb16x16Pixel = 0; |
| [[maybe_unused]] constexpr uint32_t kAfbc32x8Pixel = 1; |
| constexpr uint32_t kAfbcRGBA8888 = 5; |
| constexpr uint32_t kAfbcColorReorderR = 1; |
| constexpr uint32_t kAfbcColorReorderG = 2; |
| constexpr uint32_t kAfbcColorReorderB = 3; |
| constexpr uint32_t kAfbcColorReorderA = 4; |
| |
| class OsdRegisters { |
| public: |
| hwreg::RegisterAddr<OsdCtrlStatReg> ctrl_stat; |
| hwreg::RegisterAddr<OsdCtrlStat2Reg> ctrl_stat2; /* VIU_OSD1_CTRL_STAT2 */ |
| hwreg::RegisterAddr<OsdColorAddrReg> color_addr; /* VIU_OSD1_COLOR_ADDR */ |
| hwreg::RegisterAddr<OsdColorReg> color; /* VIU_OSD1_COLOR */ |
| hwreg::RegisterAddr<OsdTcolorAgReg> tcolor_ag0; /* VIU_OSD1_TCOLOR_AG0 */ |
| hwreg::RegisterAddr<OsdTcolorAgReg> tcolor_ag1; /* VIU_OSD1_TCOLOR_AG1 */ |
| hwreg::RegisterAddr<OsdTcolorAgReg> tcolor_ag2; /* VIU_OSD1_TCOLOR_AG2 */ |
| hwreg::RegisterAddr<OsdTcolorAgReg> tcolor_ag3; /* VIU_OSD1_TCOLOR_AG3 */ |
| hwreg::RegisterAddr<OsdBlk0CfgW0Reg> blk0_cfg_w0; /* VIU_OSD1_BLK0_CFG_W0 */ |
| hwreg::RegisterAddr<OsdBlk0CfgW1Reg> blk0_cfg_w1; /* VIU_OSD1_BLK0_CFG_W1 */ |
| hwreg::RegisterAddr<OsdBlk0CfgW2Reg> blk0_cfg_w2; /* VIU_OSD1_BLK0_CFG_W2 */ |
| hwreg::RegisterAddr<OsdBlk0CfgW3Reg> blk0_cfg_w3; /* VIU_OSD1_BLK0_CFG_W3 */ |
| hwreg::RegisterAddr<OsdBlk0CfgW4Reg> blk0_cfg_w4; /* VIU_OSD1_BLK0_CFG_W4 */ |
| hwreg::RegisterAddr<OsdBlk1CfgW4Reg> blk1_cfg_w4; /* VIU_OSD1_BLK1_CFG_W4 */ |
| hwreg::RegisterAddr<OsdBlk2CfgW4Reg> blk2_cfg_w4; /* VIU_OSD1_BLK2_CFG_W4 */ |
| hwreg::RegisterAddr<OsdFifoCtrlStatReg> fifo_ctrl_stat; /* VIU_OSD1_FIFO_CTRL_STAT */ |
| // hwreg::RegisterAddr<OsdTestRdDataReg> test_rddata;/* VIU_OSD1_TEST_RDDATA */ |
| hwreg::RegisterAddr<OsdProtCtrlReg> prot_ctrl; /* VIU_OSD1_PROT_CTRL */ |
| hwreg::RegisterAddr<OsdMaliUnpackCtrlReg> mali_unpack_ctrl; /* VIU_OSD1_MALI_UNPACK_CTRL */ |
| hwreg::RegisterAddr<OsdDimmCtrlReg> dimm_ctrl; /* VIU_OSD1_DIMM_CTRL */ |
| |
| hwreg::RegisterAddr<OsdScaleCoefIdxReg> scale_coef_idx; /* VPP_OSD_SCALE_COEF_IDX */ |
| hwreg::RegisterAddr<OsdScaleCoefReg> scale_coef; /* VPP_OSD_SCALE_COEF */ |
| hwreg::RegisterAddr<OsdVscPhaseStepReg> vsc_phase_step; /* VPP_OSD_VSC_PHASE_STEP */ |
| hwreg::RegisterAddr<OsdVscInitPhaseReg> vsc_init_phase; /* VPP_OSD_VSC_INI_PHASE */ |
| hwreg::RegisterAddr<OsdVscCtrl0Reg> vsc_ctrl0; /* VPP_OSD_VSC_CTRL0 */ |
| hwreg::RegisterAddr<OsdHscPhaseStepReg> hsc_phase_step; /* VPP_OSD_HSC_PHASE_STEP */ |
| hwreg::RegisterAddr<OsdHscInitPhaseReg> hsc_init_phase; /* VPP_OSD_HSC_INI_PHASE */ |
| hwreg::RegisterAddr<OsdHscCtrl0Reg> hsc_ctrl0; /* VPP_OSD_HSC_CTRL0 */ |
| hwreg::RegisterAddr<OsdScDummyDataReg> sc_dummy_data; /* VPP_OSD_SC_DUMMY_DATA */ |
| hwreg::RegisterAddr<OsdScCtrl0Reg> sc_ctrl0; /* VPP_OSD_SC_CTRL0 */ |
| hwreg::RegisterAddr<OsdSciWhM1Reg> sci_wh_m1; /* VPP_OSD_SCI_WH_M1 */ |
| hwreg::RegisterAddr<OsdScoHStartEndReg> sco_h_start_end; /* VPP_OSD_SCO_H_START_END */ |
| hwreg::RegisterAddr<OsdScoVStartEndReg> sco_v_start_end; /* VPP_OSD_SCO_V_START_END */ |
| hwreg::RegisterAddr<AfbcHeaderBufAddrLowS0Reg> |
| afbc_header_buf_addr_low_s; /* VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0 */ |
| hwreg::RegisterAddr<AfbcHeaderBufAddrHighS0Reg> |
| afbc_header_buf_addr_high_s; /* VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0 */ |
| hwreg::RegisterAddr<AfbcFormatSpecifierS0Reg> |
| afbc_format_specifier_s; /* VPU_MAFBC_FORMAT_SPECIFIER_S0 */ |
| hwreg::RegisterAddr<AfbcBufferWidthS0Reg> afbc_buffer_width_s; /* VPU_MAFBC_BUFFER_WIDTH_S0 */ |
| hwreg::RegisterAddr<AfbcBufferHeightS0Reg> afbc_buffer_height_s; /* VPU_MAFBC_BUFFER_HEIGHT_S0 */ |
| hwreg::RegisterAddr<AfbcBoundingBoxXStartS0Reg> |
| afbc_bounding_box_x_start_s; /* VPU_MAFBC_BOUNDING_BOX_X_START_S0 */ |
| hwreg::RegisterAddr<AfbcBoundingBoxXEndS0Reg> |
| afbc_bounding_box_x_end_s; /* VPU_MAFBC_BOUNDING_BOX_X_END_S0 */ |
| hwreg::RegisterAddr<AfbcBoundingBoxYStartS0Reg> |
| afbc_bounding_box_y_start_s; /* VPU_MAFBC_BOUNDING_BOX_Y_START_S0 */ |
| hwreg::RegisterAddr<AfbcBoundingBoxYEndS0Reg> |
| afbc_bounding_box_y_end_s; /* VPU_MAFBC_BOUNDING_BOX_Y_END_S0 */ |
| hwreg::RegisterAddr<AfbcOutputBufAddrLowS0Reg> |
| afbc_output_buf_addr_low_s; /* VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0 */ |
| hwreg::RegisterAddr<AfbcOutputBufAddrHighS0Reg> |
| afbc_output_buf_addr_high_s; /* VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0 */ |
| hwreg::RegisterAddr<AfbcOutputBufStrideS0Reg> |
| afbc_output_buf_stride_s; /* VPU_MAFBC_OUTPUT_BUF_STRIDE_S0 */ |
| hwreg::RegisterAddr<AfbcPrefetchCfgS0Reg> afbc_prefetch_cfg_s; /* VPU_MAFBC_PREFETCH_CFG_S0 */ |
| }; |
| |
| OsdRegisters osd1_registers = { |
| OsdCtrlStatReg::Get(VPU_VIU_OSD1_CTRL_STAT), |
| OsdCtrlStat2Reg::Get(VPU_VIU_OSD1_CTRL_STAT2), |
| OsdColorAddrReg::Get(VPU_VIU_OSD1_COLOR_ADDR), |
| OsdColorReg::Get(VPU_VIU_OSD1_COLOR), |
| OsdTcolorAgReg::Get(VPU_VIU_OSD1_TCOLOR_AG0), |
| OsdTcolorAgReg::Get(VPU_VIU_OSD1_TCOLOR_AG1), |
| OsdTcolorAgReg::Get(VPU_VIU_OSD1_TCOLOR_AG2), |
| OsdTcolorAgReg::Get(VPU_VIU_OSD1_TCOLOR_AG3), |
| OsdBlk0CfgW0Reg::Get(VPU_VIU_OSD1_BLK0_CFG_W0), |
| OsdBlk0CfgW1Reg::Get(VPU_VIU_OSD1_BLK0_CFG_W1), |
| OsdBlk0CfgW2Reg::Get(VPU_VIU_OSD1_BLK0_CFG_W2), |
| OsdBlk0CfgW3Reg::Get(VPU_VIU_OSD1_BLK0_CFG_W3), |
| OsdBlk0CfgW4Reg::Get(VPU_VIU_OSD1_BLK0_CFG_W4), |
| OsdBlk1CfgW4Reg::Get(VPU_VIU_OSD1_BLK1_CFG_W4), |
| OsdBlk2CfgW4Reg::Get(VPU_VIU_OSD1_BLK2_CFG_W4), |
| OsdFifoCtrlStatReg::Get(VPU_VIU_OSD1_FIFO_CTRL_STAT), |
| // OsdTestRdDataReg::Get(VPU_VIU_OSD1_TEST_RDDATA), |
| OsdProtCtrlReg::Get(VPU_VIU_OSD1_PROT_CTRL), |
| OsdMaliUnpackCtrlReg::Get(VPU_VIU_OSD1_MALI_UNPACK_CTRL), |
| OsdDimmCtrlReg::Get(VPU_VIU_OSD1_DIMM_CTRL), |
| |
| OsdScaleCoefIdxReg::Get(VPU_VPP_OSD_SCALE_COEF_IDX), |
| OsdScaleCoefReg::Get(VPU_VPP_OSD_SCALE_COEF), |
| OsdVscPhaseStepReg::Get(VPU_VPP_OSD_VSC_PHASE_STEP), |
| OsdVscInitPhaseReg::Get(VPU_VPP_OSD_VSC_INI_PHASE), |
| OsdVscCtrl0Reg::Get(VPU_VPP_OSD_VSC_CTRL0), |
| OsdHscPhaseStepReg::Get(VPU_VPP_OSD_HSC_PHASE_STEP), |
| OsdHscInitPhaseReg::Get(VPU_VPP_OSD_HSC_INI_PHASE), |
| OsdHscCtrl0Reg::Get(VPU_VPP_OSD_HSC_CTRL0), |
| OsdScDummyDataReg::Get(VPU_VPP_OSD_SC_DUMMY_DATA), |
| OsdScCtrl0Reg::Get(VPU_VPP_OSD_SC_CTRL0), |
| OsdSciWhM1Reg::Get(VPU_VPP_OSD_SCI_WH_M1), |
| OsdScoHStartEndReg::Get(VPU_VPP_OSD_SCO_H_START_END), |
| OsdScoVStartEndReg::Get(VPU_VPP_OSD_SCO_V_START_END), |
| AfbcHeaderBufAddrLowS0Reg::Get(VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0), |
| AfbcHeaderBufAddrHighS0Reg::Get(VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0), |
| AfbcFormatSpecifierS0Reg::Get(VPU_MAFBC_FORMAT_SPECIFIER_S0), |
| AfbcBufferWidthS0Reg::Get(VPU_MAFBC_BUFFER_WIDTH_S0), |
| AfbcBufferHeightS0Reg::Get(VPU_MAFBC_BUFFER_HEIGHT_S0), |
| AfbcBoundingBoxXStartS0Reg::Get(VPU_MAFBC_BOUNDING_BOX_X_START_S0), |
| AfbcBoundingBoxXEndS0Reg::Get(VPU_MAFBC_BOUNDING_BOX_X_END_S0), |
| AfbcBoundingBoxYStartS0Reg::Get(VPU_MAFBC_BOUNDING_BOX_Y_START_S0), |
| AfbcBoundingBoxYEndS0Reg::Get(VPU_MAFBC_BOUNDING_BOX_Y_END_S0), |
| AfbcOutputBufAddrLowS0Reg::Get(VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0), |
| AfbcOutputBufAddrHighS0Reg::Get(VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0), |
| AfbcOutputBufStrideS0Reg::Get(VPU_MAFBC_OUTPUT_BUF_STRIDE_S0), |
| AfbcPrefetchCfgS0Reg::Get(VPU_MAFBC_PREFETCH_CFG_S0), |
| }; |
| |
| } // namespace |
| |
| display::ConfigStamp Osd::GetLastConfigStampApplied() { return rdma_->GetLastConfigStampApplied(); } |
| |
| Osd::Osd(uint32_t fb_width, uint32_t fb_height, uint32_t display_width, uint32_t display_height, |
| inspect::Node* unused_osd_inspect_node, std::optional<fdf::MmioBuffer> vpu_mmio, |
| std::unique_ptr<RdmaEngine> rdma) |
| : vpu_mmio_(std::move(vpu_mmio)), |
| fb_width_(fb_width), |
| fb_height_(fb_height), |
| display_width_(display_width), |
| display_height_(display_height), |
| rdma_(std::move(rdma)) {} |
| |
| void Osd::Disable(display::ConfigStamp config_stamp) { |
| rdma_->StopRdma(); |
| osd1_registers.ctrl_stat.ReadFrom(&(*vpu_mmio_)).set_blk_en(0).WriteTo(&(*vpu_mmio_)); |
| rdma_->ResetConfigStamp(config_stamp); |
| } |
| |
| void Osd::Enable(void) { |
| osd1_registers.ctrl_stat.ReadFrom(&(*vpu_mmio_)).set_blk_en(1).WriteTo(&(*vpu_mmio_)); |
| } |
| |
| uint32_t Osd::FloatToFixed2_10(float f) { |
| auto fixed_num = static_cast<int32_t>(round(f * kFloatToFixed2_10ScaleFactor)); |
| |
| // Amlogic hardware accepts values [-2 2). Let's make sure the result is within this range. |
| // If not, clamp it |
| fixed_num = std::clamp(fixed_num, kMinFloatToFixed2_10, kMaxFloatToFixed2_10); |
| return fixed_num & kFloatToFixed2_10Mask; |
| } |
| |
| uint32_t Osd::FloatToFixed3_10(float f) { |
| auto fixed_num = static_cast<int32_t>(round(f * kFloatToFixed3_10ScaleFactor)); |
| |
| // Amlogic hardware accepts values [-4 4). Let's make sure the result is within this range. |
| // If not, clamp it |
| fixed_num = std::clamp(fixed_num, kMinFloatToFixed3_10, kMaxFloatToFixed3_10); |
| return fixed_num & kFloatToFixed3_10Mask; |
| } |
| |
| void Osd::SetColorCorrection(uint32_t rdma_table_idx, const display_config_t* config) { |
| if (!config->cc_flags) { |
| // Disable color conversion engine |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_EN_CTRL, |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_EN_CTRL) & ~(1 << 0)); |
| return; |
| } |
| |
| // Set enable bit |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_EN_CTRL, |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_EN_CTRL) | (1 << 0)); |
| |
| // Load PreOffset values (or 0 if none entered) |
| auto offset0_1 = (config->cc_flags & COLOR_CONVERSION_PREOFFSET |
| ? (FloatToFixed2_10(config->cc_preoffsets[0]) << 16 | |
| FloatToFixed2_10(config->cc_preoffsets[1]) << 0) |
| : 0); |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_PRE_OFFSET0_1, offset0_1); |
| auto offset2 = (config->cc_flags & COLOR_CONVERSION_PREOFFSET |
| ? (FloatToFixed2_10(config->cc_preoffsets[2]) << 0) |
| : 0); |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_PRE_OFFSET2, offset2); |
| // TODO(b/182481217): remove when this bug is closed. |
| zxlogf(TRACE, "pre offset0_1=%u offset2=%u", offset0_1, offset2); |
| |
| // Load PostOffset values (or 0 if none entered) |
| offset0_1 = (config->cc_flags & COLOR_CONVERSION_POSTOFFSET |
| ? (FloatToFixed2_10(config->cc_postoffsets[0]) << 16 | |
| FloatToFixed2_10(config->cc_postoffsets[1]) << 0) |
| : 0); |
| offset2 = (config->cc_flags & COLOR_CONVERSION_PREOFFSET |
| ? (FloatToFixed2_10(config->cc_postoffsets[2]) << 0) |
| : 0); |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_OFFSET0_1, offset0_1); |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_OFFSET2, offset2); |
| // TODO(b/182481217): remove when this bug is closed. |
| zxlogf(TRACE, "post offset0_1=%u offset2=%u", offset0_1, offset2); |
| |
| // clang-format off |
| const float identity[3][3] = { |
| {1, 0, 0,}, |
| {0, 1, 0,}, |
| {0, 0, 1,}, |
| }; |
| // clang-format on |
| |
| const auto* ccm = |
| (config->cc_flags & COLOR_CONVERSION_COEFFICIENTS) ? config->cc_coefficients : identity; |
| |
| // Load up the coefficient matrix registers |
| auto coef00_01 = FloatToFixed3_10(ccm[0][0]) << 16 | FloatToFixed3_10(ccm[0][1]) << 0; |
| auto coef02_10 = FloatToFixed3_10(ccm[0][2]) << 16 | FloatToFixed3_10(ccm[1][0]) << 0; |
| auto coef11_12 = FloatToFixed3_10(ccm[1][1]) << 16 | FloatToFixed3_10(ccm[1][2]) << 0; |
| auto coef20_21 = FloatToFixed3_10(ccm[2][0]) << 16 | FloatToFixed3_10(ccm[2][1]) << 0; |
| auto coef22 = FloatToFixed3_10(ccm[2][2]) << 0; |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_COEF00_01, coef00_01); |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_COEF02_10, coef02_10); |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_COEF11_12, coef11_12); |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_COEF20_21, coef20_21); |
| rdma_->SetRdmaTableValue(rdma_table_idx, IDX_MATRIX_COEF22, coef22); |
| // TODO(b/182481217): remove when this bug is closed. |
| zxlogf(TRACE, "color correction regs 00_01=%xu 02_12=%xu 11_12=%xu 20_21=%u 22=%xu", coef00_01, |
| coef02_10, coef11_12, coef20_21, coef22); |
| } |
| |
| void Osd::FlipOnVsync(uint8_t idx, const display_config_t* config, |
| display::ConfigStamp config_stamp) { |
| auto info = reinterpret_cast<ImageInfo*>(config[0].layer_list[0]->cfg.primary.image.handle); |
| const int next_table_idx = rdma_->GetNextAvailableRdmaTableIndex(); |
| if (next_table_idx < 0) { |
| zxlogf(ERROR, "No table available!"); |
| return; |
| } |
| |
| zxlogf(TRACE, "Table index %d used", next_table_idx); |
| zxlogf(TRACE, "AFBC %s", info->is_afbc ? "enabled" : "disabled"); |
| |
| if ((config[0].mode.h_addressable != display_width_) || |
| (config[0].mode.v_addressable != display_height_)) { |
| zxlogf(INFO, "Mode change (%d x %d) to (%d x %d)", display_width_, display_height_, |
| config[0].mode.h_addressable, config[0].mode.v_addressable); |
| display_width_ = config[0].mode.h_addressable; |
| display_height_ = config[0].mode.v_addressable; |
| fb_width_ = config[0].mode.h_addressable; |
| fb_height_ = config[0].mode.v_addressable; |
| HwInit(); |
| } |
| |
| auto cfg_w0 = osd1_registers.blk0_cfg_w0.FromValue(0); |
| if (info->is_afbc) { |
| // AFBC: Enable sourcing from mali + configure as big endian |
| cfg_w0.set_mali_src_en(1).set_little_endian(0); |
| } else { |
| // Update CFG_W0 with correct Canvas Index |
| cfg_w0.set_mali_src_en(0).set_little_endian(1).set_tbl_addr(idx); |
| } |
| cfg_w0.set_blk_mode(OsdBlk0CfgW0Reg::kBlockMode32Bit); |
| |
| switch (info->pixel_format.pixel_format) { |
| case fuchsia_images2::PixelFormat::kR8G8B8A8: |
| cfg_w0.set_color_matrix(OsdBlk0CfgW0Reg::kColorMatrixAbgr8888); |
| break; |
| case fuchsia_images2::PixelFormat::kBgra32: |
| cfg_w0.set_color_matrix(OsdBlk0CfgW0Reg::kColorMatrixArgb8888); |
| break; |
| default: |
| // This should never happen. The image validity is guaranteed in |
| // ImportImage() / CheckConfiguration(). |
| ZX_ASSERT_MSG(false, "Unsupported image format %u", |
| static_cast<uint32_t>(info->pixel_format.pixel_format)); |
| return; |
| } |
| |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_BLK0_CFG_W0, cfg_w0.reg_value()); |
| |
| // Configure ctrl_stat and ctrl_stat2 registers |
| auto osd_ctrl_stat_val = osd1_registers.ctrl_stat.ReadFrom(&(*vpu_mmio_)); |
| auto osd_ctrl_stat2_val = osd1_registers.ctrl_stat2.ReadFrom(&(*vpu_mmio_)); |
| |
| // enable OSD Block |
| osd_ctrl_stat_val.set_blk_en(1); |
| |
| // Amlogic supports two types of alpha blending: |
| // Global: This alpha value is applied to the entire plane (i.e. all pixels) |
| // Per-Pixel: Each pixel will be multiplied by its corresponding alpha channel |
| // |
| // If alpha blending is disabled by the client or we are supporting a format that does |
| // not have an alpha channel, we need to: |
| // a) Set global alpha multiplier to 1 (i.e. 0xFF) |
| // b) Enable "replaced_alpha" and set its value to 0xFF. This will effectively |
| // tell the hardware to replace the value found in alpha channel with the "replaced" |
| // value |
| // |
| // If alpha blending is enabled but alpha_layer_val is NaN: |
| // - Set global alpha multiplier to 1 (i.e. 0xFF) |
| // - Disable "replaced_alpha" which allows hardware to use per-pixel alpha channel. |
| // |
| // If alpha blending is enabled and alpha_layer_val has a value: |
| // - Set global alpha multiplier to alpha_layer_val |
| // - Disable "replaced_alpha" which allows hardware to use per-pixel alpha channel. |
| |
| // Load default values: Set global alpha to 1 and enable replaced_alpha. |
| osd_ctrl_stat2_val.set_replaced_alpha_en(1).set_replaced_alpha(kMaximumAlpha); |
| osd_ctrl_stat_val.set_global_alpha(kMaximumAlpha); |
| |
| // This is guaranteed by AmlogicDisplay::CheckConfiguration(). |
| ZX_DEBUG_ASSERT(config->layer_count > 0); |
| ZX_DEBUG_ASSERT(config->layer_list[0]->type == LAYER_TYPE_PRIMARY); |
| const primary_layer_t& primary_layer = config->layer_list[0]->cfg.primary; |
| if (primary_layer.alpha_mode != ALPHA_DISABLE) { |
| // If a global alpha value is provided, apply it. |
| if (!isnan(primary_layer.alpha_layer_val)) { |
| auto num = static_cast<uint8_t>(round(primary_layer.alpha_layer_val * kMaximumAlpha)); |
| osd_ctrl_stat_val.set_global_alpha(num); |
| } |
| } |
| |
| // Use linear address for AFBC, Canvas otherwise |
| osd_ctrl_stat_val.set_osd_mem_mode(info->is_afbc ? 1 : 0); |
| osd_ctrl_stat2_val.set_pending_status_cleanup(1); |
| |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_CTRL_STAT, osd_ctrl_stat_val.reg_value()); |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_CTRL_STAT2, osd_ctrl_stat2_val.reg_value()); |
| |
| if (info->is_afbc) { |
| // Line Stride calculation based on vendor code |
| auto a = fbl::round_up(fbl::round_up(info->image_width * 4, 16u) / 16, 2u); |
| auto r = osd1_registers.blk2_cfg_w4.FromValue(0).set_linear_stride(a).reg_value(); |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_BLK2_CFG_W4, r); |
| |
| // Set AFBC's Physical address since it does not use Canvas |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_AFBC_HEAD_BUF_ADDR_LOW, |
| (info->paddr & 0xFFFFFFFF)); |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_AFBC_HEAD_BUF_ADDR_HIGH, (info->paddr >> 32)); |
| |
| // Set OSD to unpack Mali source |
| auto upackreg = osd1_registers.mali_unpack_ctrl.ReadFrom(&(*vpu_mmio_)).set_mali_unpack_en(1); |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_MALI_UNPACK_CTRL, upackreg.reg_value()); |
| |
| // Switch OSD to Mali Source |
| auto miscctrl = OsdPathMiscCtrlReg::Get(VPU_OSD_PATH_MISC_CTRL) |
| .ReadFrom(&(*vpu_mmio_)) |
| .set_osd1_mali_sel(1); |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_PATH_MISC_CTRL, miscctrl.reg_value()); |
| |
| // S0 is our index of 0, which is programmed for OSD1 |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_AFBC_SURFACE_CFG, |
| AfbcSurfaceCfgReg::Get(VPU_MAFBC_SURFACE_CFG) |
| .ReadFrom(&(*vpu_mmio_)) |
| .set_cont(0) |
| .set_s0_en(1) |
| .reg_value()); |
| // set command - This uses a separate RDMA Table |
| rdma_->SetAfbcRdmaTableValue( |
| AfbcCommandReg::Get(VPU_MAFBC_COMMAND).FromValue(0).set_direct_swap(1).reg_value()); |
| } else { |
| // Set OSD to unpack Normal source |
| auto upackreg = osd1_registers.mali_unpack_ctrl.ReadFrom(&(*vpu_mmio_)).set_mali_unpack_en(0); |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_MALI_UNPACK_CTRL, upackreg.reg_value()); |
| |
| // Switch OSD to DDR Source |
| auto miscctrl = OsdPathMiscCtrlReg::Get(VPU_OSD_PATH_MISC_CTRL) |
| .ReadFrom(&(*vpu_mmio_)) |
| .set_osd1_mali_sel(0); |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_PATH_MISC_CTRL, miscctrl.reg_value()); |
| |
| // Disable afbc sourcing |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_AFBC_SURFACE_CFG, |
| AfbcSurfaceCfgReg::Get(VPU_MAFBC_SURFACE_CFG) |
| .ReadFrom(&(*vpu_mmio_)) |
| .set_s0_en(0) |
| .reg_value()); |
| // clear command - This uses a separate RDMA Table |
| rdma_->SetAfbcRdmaTableValue( |
| AfbcCommandReg::Get(VPU_MAFBC_COMMAND).FromValue(0).set_direct_swap(0).reg_value()); |
| } |
| |
| SetColorCorrection(next_table_idx, config); |
| |
| // update last element of table which will be used to indicate whether RDMA operation was |
| // completed or not |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_RDMA_CFG_STAMP_HIGH, (config_stamp.value() >> 32)); |
| rdma_->SetRdmaTableValue(next_table_idx, IDX_RDMA_CFG_STAMP_LOW, |
| (config_stamp.value() & 0xFFFFFFFF)); |
| |
| rdma_->FlushRdmaTable(next_table_idx); |
| if (info->is_afbc) { |
| rdma_->FlushAfbcRdmaTable(); |
| } |
| |
| rdma_->ExecRdmaTable(next_table_idx, config_stamp, info->is_afbc); |
| } |
| |
| void Osd::DefaultSetup() { |
| // osd blend ctrl |
| WRITE32_REG(VPU, VIU_OSD_BLEND_CTRL, |
| 4 << 29 | 0 << 27 | // blend2_premult_en |
| 1 << 26 | // blend_din0 input to blend0 |
| 0 << 25 | // blend1_dout to blend2 |
| 0 << 24 | // blend1_din3 input to blend1 |
| 1 << 20 | // blend_din_en |
| 0 << 16 | // din_premult_en |
| 1 << 0); // din_reoder_sel = OSD1 |
| |
| // vpp osd1 blend ctrl |
| WRITE32_REG(VPU, OSD1_BLEND_SRC_CTRL, |
| (0 & 0xf) << 0 | (0 & 0x1) << 4 | (3 & 0xf) << 8 | // postbld_src3_sel |
| (0 & 0x1) << 16 | // postbld_osd1_premult |
| (1 & 0x1) << 20); |
| // vpp osd2 blend ctrl |
| WRITE32_REG(VPU, OSD2_BLEND_SRC_CTRL, |
| (0 & 0xf) << 0 | (0 & 0x1) << 4 | (0 & 0xf) << 8 | // postbld_src4_sel |
| (0 & 0x1) << 16 | // postbld_osd2_premult |
| (1 & 0x1) << 20); |
| |
| // used default dummy data |
| WRITE32_REG(VPU, VIU_OSD_BLEND_DUMMY_DATA0, 0x0 << 16 | 0x0 << 8 | 0x0); |
| // used default dummy alpha data |
| WRITE32_REG(VPU, VIU_OSD_BLEND_DUMMY_ALPHA, 0x0 << 20 | 0x0 << 11 | 0x0); |
| |
| // osdx setting |
| WRITE32_REG(VPU, VPU_VIU_OSD_BLEND_DIN0_SCOPE_H, (fb_width_ - 1) << 16); |
| |
| WRITE32_REG(VPU, VPU_VIU_OSD_BLEND_DIN0_SCOPE_V, (fb_height_ - 1) << 16); |
| |
| WRITE32_REG(VPU, VIU_OSD_BLEND_BLEND0_SIZE, fb_height_ << 16 | fb_width_); |
| WRITE32_REG(VPU, VIU_OSD_BLEND_BLEND1_SIZE, fb_height_ << 16 | fb_width_); |
| SET_BIT32(VPU, DOLBY_PATH_CTRL, 0x3, 2, 2); |
| |
| WRITE32_REG(VPU, VPP_OSD1_IN_SIZE, fb_height_ << 16 | fb_width_); |
| |
| // setting blend scope |
| WRITE32_REG(VPU, VPP_OSD1_BLD_H_SCOPE, 0 << 16 | (fb_width_ - 1)); |
| WRITE32_REG(VPU, VPP_OSD1_BLD_V_SCOPE, 0 << 16 | (fb_height_ - 1)); |
| |
| // Set geometry to normal mode |
| uint32_t data32 = ((fb_width_ - 1) & 0xfff) << 16; |
| WRITE32_REG(VPU, VPU_VIU_OSD1_BLK0_CFG_W3, data32); |
| data32 = ((fb_height_ - 1) & 0xfff) << 16; |
| WRITE32_REG(VPU, VPU_VIU_OSD1_BLK0_CFG_W4, data32); |
| |
| WRITE32_REG(VPU, VPU_VIU_OSD1_BLK0_CFG_W1, ((fb_width_ - 1) & 0x1fff) << 16); |
| WRITE32_REG(VPU, VPU_VIU_OSD1_BLK0_CFG_W2, ((fb_height_ - 1) & 0x1fff) << 16); |
| |
| // enable osd blk0 |
| osd1_registers.ctrl_stat.ReadFrom(&(*vpu_mmio_)) |
| .set_rsv(0) |
| .set_osd_mem_mode(0) |
| .set_premult_en(0) |
| .set_blk_en(1) |
| .WriteTo(&(*vpu_mmio_)); |
| } |
| |
| void Osd::EnableScaling(bool enable) { |
| int hf_phase_step, vf_phase_step; |
| int src_w, src_h, dst_w, dst_h; |
| int bot_ini_phase; |
| int vsc_ini_rcv_num, vsc_ini_rpt_p0_num; |
| int hsc_ini_rcv_num, hsc_ini_rpt_p0_num; |
| int hf_bank_len = 4; |
| int vf_bank_len = 0; |
| uint32_t data32 = 0x0; |
| |
| vf_bank_len = 4; |
| hsc_ini_rcv_num = hf_bank_len; |
| vsc_ini_rcv_num = vf_bank_len; |
| hsc_ini_rpt_p0_num = (hf_bank_len / 2 - 1) > 0 ? (hf_bank_len / 2 - 1) : 0; |
| vsc_ini_rpt_p0_num = (vf_bank_len / 2 - 1) > 0 ? (vf_bank_len / 2 - 1) : 0; |
| src_w = fb_width_; |
| src_h = fb_height_; |
| dst_w = display_width_; |
| dst_h = display_height_; |
| |
| data32 = 0x0; |
| if (enable) { |
| /* enable osd scaler */ |
| data32 |= 1 << 2; /* enable osd scaler */ |
| data32 |= 1 << 3; /* enable osd scaler path */ |
| WRITE32_REG(VPU, VPU_VPP_OSD_SC_CTRL0, data32); |
| } else { |
| /* disable osd scaler path */ |
| WRITE32_REG(VPU, VPU_VPP_OSD_SC_CTRL0, 0); |
| } |
| hf_phase_step = (src_w << 18) / dst_w; |
| hf_phase_step = (hf_phase_step << 6); |
| vf_phase_step = (src_h << 20) / dst_h; |
| bot_ini_phase = 0; |
| vf_phase_step = (vf_phase_step << 4); |
| |
| /* config osd scaler in/out hv size */ |
| data32 = 0x0; |
| if (enable) { |
| data32 = (((src_h - 1) & 0x1fff) | ((src_w - 1) & 0x1fff) << 16); |
| WRITE32_REG(VPU, VPU_VPP_OSD_SCI_WH_M1, data32); |
| data32 = (((display_width_ - 1) & 0xfff)); |
| WRITE32_REG(VPU, VPU_VPP_OSD_SCO_H_START_END, data32); |
| data32 = (((display_height_ - 1) & 0xfff)); |
| WRITE32_REG(VPU, VPU_VPP_OSD_SCO_V_START_END, data32); |
| } |
| data32 = 0x0; |
| if (enable) { |
| data32 |= |
| (vf_bank_len & 0x7) | ((vsc_ini_rcv_num & 0xf) << 3) | ((vsc_ini_rpt_p0_num & 0x3) << 8); |
| data32 |= 1 << 24; |
| } |
| WRITE32_REG(VPU, VPU_VPP_OSD_VSC_CTRL0, data32); |
| data32 = 0x0; |
| if (enable) { |
| data32 |= |
| (hf_bank_len & 0x7) | ((hsc_ini_rcv_num & 0xf) << 3) | ((hsc_ini_rpt_p0_num & 0x3) << 8); |
| data32 |= 1 << 22; |
| } |
| WRITE32_REG(VPU, VPU_VPP_OSD_HSC_CTRL0, data32); |
| data32 = 0x0; |
| if (enable) { |
| data32 |= (bot_ini_phase & 0xffff) << 16; |
| SET_BIT32(VPU, VPU_VPP_OSD_HSC_PHASE_STEP, hf_phase_step, 0, 28); |
| SET_BIT32(VPU, VPU_VPP_OSD_HSC_INI_PHASE, 0, 0, 16); |
| SET_BIT32(VPU, VPU_VPP_OSD_VSC_PHASE_STEP, vf_phase_step, 0, 28); |
| WRITE32_REG(VPU, VPU_VPP_OSD_VSC_INI_PHASE, data32); |
| } |
| } |
| |
| void Osd::SetMinimumRgb(uint8_t minimum_rgb) { |
| // According to spec, minimum rgb should be set as follows: |
| // Shift value by 2bits (8bit -> 10bit) and write new value for |
| // each channel separately. |
| VppClipMisc1Reg::Get() |
| .FromValue(0) |
| .set_r_clamp(minimum_rgb << 2) |
| .set_g_clamp(minimum_rgb << 2) |
| .set_b_clamp(minimum_rgb << 2) |
| .WriteTo(&(*vpu_mmio_)); |
| } |
| |
| // These configuration could be done during initialization. |
| zx_status_t Osd::ConfigAfbc() { |
| // The format specifier must match the sysmem format modifier flags specified |
| // in AmlogicDisplay::DisplayControllerImplSetBufferCollectionConstraints(). |
| // |
| // Note RGBA8888 works for both RGBA and BGRA formats. The color channels can |
| // be reordered by setting MALI_UNPACK_CTRL register. |
| osd1_registers.afbc_format_specifier_s.FromValue(0) |
| .set_block_split_mode_enabled(true) |
| .set_tiled_header_enabled(false) |
| .set_yuv_transform_enabled(true) |
| .set_super_block_aspect(kAfbcb16x16Pixel) |
| .set_pixel_format(kAfbcRGBA8888) |
| .WriteTo(&(*vpu_mmio_)); |
| |
| // Setup color RGBA channel order |
| osd1_registers.mali_unpack_ctrl.ReadFrom(&(*vpu_mmio_)) |
| .set_r(kAfbcColorReorderR) |
| .set_g(kAfbcColorReorderG) |
| .set_b(kAfbcColorReorderB) |
| .set_a(kAfbcColorReorderA) |
| .WriteTo(&(*vpu_mmio_)); |
| |
| // Set afbc input buffer width/height in pixel |
| osd1_registers.afbc_buffer_width_s.FromValue(0).set_buffer_width(fb_width_).WriteTo( |
| &(*vpu_mmio_)); |
| osd1_registers.afbc_buffer_height_s.FromValue(0) |
| .set_buffer_height(fb_height_) |
| .WriteTo(&(*vpu_mmio_)); |
| |
| // Set afbc input buffer |
| osd1_registers.afbc_bounding_box_x_start_s.FromValue(0).set_buffer_x_start(0).WriteTo( |
| &(*vpu_mmio_)); |
| osd1_registers.afbc_bounding_box_x_end_s.FromValue(0) |
| .set_buffer_x_end(fb_width_ - 1) // vendor code has width - 1 - 1, which is technically |
| // incorrect and gives the same result as this. |
| .WriteTo(&(*vpu_mmio_)); |
| osd1_registers.afbc_bounding_box_y_start_s.FromValue(0).set_buffer_y_start(0).WriteTo( |
| &(*vpu_mmio_)); |
| osd1_registers.afbc_bounding_box_y_end_s.FromValue(0) |
| .set_buffer_y_end(fb_height_ - |
| 1) // vendor code has height -1 -1, but that cuts off the bottom row. |
| .WriteTo(&(*vpu_mmio_)); |
| |
| // Set output buffer stride |
| osd1_registers.afbc_output_buf_stride_s.FromValue(0) |
| .set_output_buffer_stride(fb_width_ * 4) |
| .WriteTo(&(*vpu_mmio_)); |
| |
| // Set afbc output buffer index |
| // The way this is calculated based on vendor code is as follows: |
| // Take OSD being used (1-based index): Therefore OSD1 -> index 1 |
| // out_addr = index << 24 |
| osd1_registers.afbc_output_buf_addr_low_s.FromValue(0).set_output_buffer_addr(1 << 24).WriteTo( |
| &(*vpu_mmio_)); |
| osd1_registers.afbc_output_buf_addr_high_s.FromValue(0).set_output_buffer_addr(0).WriteTo( |
| &(*vpu_mmio_)); |
| |
| // Set linear address to the out_addr mentioned above |
| osd1_registers.blk1_cfg_w4.FromValue(0).set_frame_addr(1 << 24).WriteTo(&(*vpu_mmio_)); |
| |
| return ZX_OK; |
| } |
| |
| void Osd::HwInit() { |
| // Setup VPP horizontal width |
| WRITE32_REG(VPU, VPP_POSTBLEND_H_SIZE, display_width_); |
| |
| // init vpu fifo control register |
| uint32_t regVal = READ32_REG(VPU, VPP_OFIFO_SIZE); |
| regVal = 0xfff << 20; |
| regVal |= (0xfff + 1); |
| WRITE32_REG(VPU, VPP_OFIFO_SIZE, regVal); |
| |
| // init osd fifo control and set DDR request priority to be urgent |
| regVal = 1; |
| regVal |= 4 << 5; // hold_fifo_lines |
| regVal |= 1 << 10; // burst_len_sel 3 = 64. This bit is split between 10 and 31 |
| regVal |= 2 << 22; |
| regVal |= 2 << 24; |
| regVal |= 1 << 31; |
| regVal |= 32 << 12; // fifo_depth_val: 32*8 = 256 |
| WRITE32_REG(VPU, VPU_VIU_OSD1_FIFO_CTRL_STAT, regVal); |
| WRITE32_REG(VPU, VPU_VIU_OSD2_FIFO_CTRL_STAT, regVal); |
| |
| SET_MASK32(VPU, VPP_MISC, VPP_POSTBLEND_EN); |
| CLEAR_MASK32(VPU, VPP_MISC, VPP_PREBLEND_EN); |
| |
| osd1_registers.ctrl_stat.FromValue(0) |
| .set_blk_en(1) |
| .set_global_alpha(kMaximumAlpha) |
| .set_osd_en(1) |
| .WriteTo(&(*vpu_mmio_)); |
| |
| // TODO: split this method into HwInit for each OSD. |
| Osd2CtrlStatReg::Get() |
| .FromValue(0) |
| .set_blk_en(1) |
| .set_global_alpha(kMaximumAlpha) |
| .set_osd_en(1) |
| .WriteTo(&(*vpu_mmio_)); |
| |
| DefaultSetup(); |
| |
| EnableScaling(false); |
| |
| // Apply scale coefficients |
| osd1_registers.scale_coef_idx.ReadFrom(&(*vpu_mmio_)) |
| .set_hi_res_coef(0) |
| .set_h_coef(0) |
| .set_index(0) |
| .WriteTo(&(*vpu_mmio_)); |
| for (unsigned int i : osd_filter_coefs_bicubic) { |
| osd1_registers.scale_coef.FromValue(i).WriteTo(&(*vpu_mmio_)); |
| } |
| |
| osd1_registers.scale_coef_idx.ReadFrom(&(*vpu_mmio_)) |
| .set_hi_res_coef(0) |
| .set_h_coef(1) |
| .set_index(0) |
| .WriteTo(&(*vpu_mmio_)); |
| for (unsigned int i : osd_filter_coefs_bicubic) { |
| osd1_registers.scale_coef.FromValue(i).WriteTo(&(*vpu_mmio_)); |
| } |
| |
| // update blending |
| WRITE32_REG(VPU, VPP_OSD1_BLD_H_SCOPE, 0 << 16 | (display_width_ - 1)); |
| WRITE32_REG(VPU, VPP_OSD1_BLD_V_SCOPE, 0 << 16 | (display_height_ - 1)); |
| WRITE32_REG(VPU, VPU_VPP_OUT_H_V_SIZE, display_width_ << 16 | display_height_); |
| |
| // Configure AFBC Engine's one-time programmable fields, so it's ready |
| ConfigAfbc(); |
| } |
| |
| #define REG_OFFSET (0x20 << 2) |
| void Osd::Dump() { |
| DumpNonRdmaRegisters(); |
| rdma_->DumpRdmaRegisters(); |
| } |
| |
| #define LOG_REG(reg) zxlogf(INFO, "reg[0x%x]: 0x%08x " #reg, (reg), READ32_REG(VPU, (reg))) |
| #define LOG_REG_INSTANCE(reg, offset, index) \ |
| zxlogf(INFO, "reg[0x%x]: 0x%08x " #reg " #%d", (reg) + (offset), READ32_REG(VPU, (reg)), \ |
| index + 1) |
| void Osd::DumpNonRdmaRegisters() { |
| uint32_t offset = 0; |
| uint32_t index = 0; |
| |
| LOG_REG(VPU_VIU_VENC_MUX_CTRL); |
| LOG_REG(VPU_VPP_MISC); |
| LOG_REG(VPU_VPP_OFIFO_SIZE); |
| LOG_REG(VPU_VPP_HOLD_LINES); |
| |
| LOG_REG(VPU_OSD_PATH_MISC_CTRL); |
| LOG_REG(VPU_VIU_OSD_BLEND_CTRL); |
| LOG_REG(VPU_VIU_OSD_BLEND_DIN0_SCOPE_H); |
| LOG_REG(VPU_VIU_OSD_BLEND_DIN0_SCOPE_V); |
| LOG_REG(VPU_VIU_OSD_BLEND_DIN1_SCOPE_H); |
| LOG_REG(VPU_VIU_OSD_BLEND_DIN1_SCOPE_V); |
| LOG_REG(VPU_VIU_OSD_BLEND_DIN2_SCOPE_H); |
| LOG_REG(VPU_VIU_OSD_BLEND_DIN2_SCOPE_V); |
| LOG_REG(VPU_VIU_OSD_BLEND_DIN3_SCOPE_H); |
| LOG_REG(VPU_VIU_OSD_BLEND_DIN3_SCOPE_V); |
| LOG_REG(VPU_VIU_OSD_BLEND_DUMMY_DATA0); |
| LOG_REG(VPU_VIU_OSD_BLEND_DUMMY_ALPHA); |
| LOG_REG(VPU_VIU_OSD_BLEND_BLEND0_SIZE); |
| LOG_REG(VPU_VIU_OSD_BLEND_BLEND1_SIZE); |
| |
| LOG_REG(VPU_VPP_OSD1_IN_SIZE); |
| LOG_REG(VPU_VPP_OSD1_BLD_H_SCOPE); |
| LOG_REG(VPU_VPP_OSD1_BLD_V_SCOPE); |
| LOG_REG(VPU_VPP_OSD2_BLD_H_SCOPE); |
| LOG_REG(VPU_VPP_OSD2_BLD_V_SCOPE); |
| LOG_REG(OSD1_BLEND_SRC_CTRL); |
| LOG_REG(OSD2_BLEND_SRC_CTRL); |
| LOG_REG(VPU_VPP_POSTBLEND_H_SIZE); |
| LOG_REG(VPU_VPP_OUT_H_V_SIZE); |
| |
| LOG_REG(VPU_VPP_OSD_SC_CTRL0); |
| LOG_REG(VPU_VPP_OSD_SCI_WH_M1); |
| LOG_REG(VPU_VPP_OSD_SCO_H_START_END); |
| LOG_REG(VPU_VPP_OSD_SCO_V_START_END); |
| LOG_REG(VPU_VPP_POSTBLEND_H_SIZE); |
| for (index = 0; index < 2; index++) { |
| if (index == 1) |
| offset = REG_OFFSET; |
| LOG_REG_INSTANCE(VPU_VIU_OSD1_FIFO_CTRL_STAT, offset, index); |
| LOG_REG_INSTANCE(VPU_VIU_OSD1_CTRL_STAT, offset, index); |
| LOG_REG_INSTANCE(VPU_VIU_OSD1_CTRL_STAT2, offset, index); |
| LOG_REG_INSTANCE(VPU_VIU_OSD1_BLK0_CFG_W0, offset, index); |
| LOG_REG_INSTANCE(VPU_VIU_OSD1_BLK0_CFG_W1, offset, index); |
| LOG_REG_INSTANCE(VPU_VIU_OSD1_BLK0_CFG_W2, offset, index); |
| LOG_REG_INSTANCE(VPU_VIU_OSD1_BLK0_CFG_W3, offset, index); |
| if (index == 1) { |
| LOG_REG(VPU_VIU_OSD2_BLK0_CFG_W4); |
| } else { |
| LOG_REG(VPU_VIU_OSD1_BLK0_CFG_W4); |
| } |
| } |
| |
| zxlogf(INFO, "Dumping all Color Correction Matrix related Registers"); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_COEF00_01 = 0x%x", |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF00_01)); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_COEF02_10 = 0x%x", |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF02_10)); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_COEF11_12 = 0x%x", |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF11_12)); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_COEF20_21 = 0x%x", |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF20_21)); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_COEF22 = 0x%x", vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF22)); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_OFFSET0_1 = 0x%x", |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_OFFSET0_1)); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_OFFSET2 = 0x%x", |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_OFFSET2)); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_PRE_OFFSET0_1 = 0x%x", |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_PRE_OFFSET0_1)); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_PRE_OFFSET2 = 0x%x", |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_PRE_OFFSET2)); |
| zxlogf(INFO, "VPU_VPP_POST_MATRIX_EN_CTRL = 0x%x", |
| vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_EN_CTRL)); |
| } |
| |
| void Osd::Release() { |
| Disable(); |
| rdma_->Release(); |
| thrd_join(rdma_irq_thread_, nullptr); |
| } |
| |
| // static |
| zx::result<std::unique_ptr<Osd>> Osd::Create(ddk::PDevFidl* pdev, uint32_t fb_width, |
| uint32_t fb_height, uint32_t display_width, |
| uint32_t display_height, inspect::Node* osd_node) { |
| std::optional<fdf::MmioBuffer> vpu_mmio; |
| // Map vpu mmio used by the OSD object |
| zx_status_t status = pdev->MapMmio(MMIO_VPU, &vpu_mmio); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "osd: Could not map VPU mmio"); |
| return zx::error(status); |
| } |
| |
| auto rdma_or_status = RdmaEngine::Create(pdev, osd_node); |
| if (rdma_or_status.is_error()) { |
| return zx::error(rdma_or_status.status_value()); |
| } |
| |
| fbl::AllocChecker ac; |
| std::unique_ptr<Osd> self(new (&ac) |
| Osd(fb_width, fb_height, display_width, display_height, osd_node, |
| std::move(vpu_mmio), std::move(rdma_or_status.value()))); |
| if (!ac.check()) { |
| return zx::error(ZX_ERR_NO_MEMORY); |
| } |
| |
| status = self->rdma_->SetupRdma(&(*self->vpu_mmio_)); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "Could not setup RDMA"); |
| return zx::error(status); |
| } |
| |
| // TODO(rlb): consider moving thread creation into RdmaEngine with appropriate |
| // facilities for controlling the thread from test code. |
| auto start_thread = [](void* arg) { return static_cast<RdmaEngine*>(arg)->RdmaIrqThread(); }; |
| status = thrd_create_with_name(&self->rdma_irq_thread_, start_thread, self->rdma_.get(), |
| "rdma_irq_thread"); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "Could not create rdma_thread"); |
| return zx::error(status); |
| } |
| |
| return zx::ok(self.release()); |
| } |
| |
| } // namespace amlogic_display |