diff --git a/zircon/system/dev/display/astro-display/astro-display.cpp b/zircon/system/dev/display/astro-display/astro-display.cpp index 88b56dd631d52ebac0cb4f7a6fe2d7cc59d869be..3df1589d174a3cff05a5c742ce7b3af37c15a78e 100644 --- a/zircon/system/dev/display/astro-display/astro-display.cpp +++ b/zircon/system/dev/display/astro-display/astro-display.cpp @@ -384,10 +384,31 @@ uint32_t AstroDisplay::DisplayControllerImplCheckConfiguration( fbl::AutoLock lock(&display_lock_); - bool success; - if (display_configs[0]->layer_count != 1) { - success = display_configs[0]->layer_count == 0; - } else { + bool success = true; + + if (display_configs[0]->layer_count > 1) { + // We only support 1 layer + success = false; + } + + if (success && display_configs[0]->cc_flags) { + // Make sure cc values are correct + if (display_configs[0]->cc_flags & COLOR_CONVERSION_PREOFFSET) { + for (int i = 0; i < 3; i++) { + success = success && display_configs[0]->cc_preoffsets[i] > -1; + success = success && display_configs[0]->cc_preoffsets[i] < 1; + } + } + if (success && display_configs[0]->cc_flags & COLOR_CONVERSION_POSTOFFSET) { + for (int i = 0; i < 3; i++) { + success = success && display_configs[0]->cc_postoffsets[i] > -1; + success = success && display_configs[0]->cc_postoffsets[i] < 1; + } + } + } + + if (success) { + // Make sure ther layer configuration is supported const primary_layer_t& layer = display_configs[0]->layer_list[0]->cfg.primary; frame_t frame = { .x_pos = 0, .y_pos = 0, .width = width_, .height = height_, @@ -398,7 +419,6 @@ uint32_t AstroDisplay::DisplayControllerImplCheckConfiguration( && layer.image.height == height_ && memcmp(&layer.dest_frame, &frame, sizeof(frame_t)) == 0 && memcmp(&layer.src_frame, &frame, sizeof(frame_t)) == 0 - && display_configs[0]->cc_flags == 0 && layer.alpha_mode == ALPHA_DISABLE; } if (!success) { @@ -406,7 +426,6 @@ uint32_t AstroDisplay::DisplayControllerImplCheckConfiguration( for (unsigned i = 1; i < display_configs[0]->layer_count; i++) { layer_cfg_results[0][i] = CLIENT_MERGE_SRC; } - layer_cfg_result_count[0] = display_configs[0]->layer_count; } return CONFIG_DISPLAY_OK; } @@ -433,7 +452,7 @@ void AstroDisplay::DisplayControllerImplApplyConfiguration(const display_config_ addr = (uint8_t) (uint64_t) display_configs[0]->layer_list[0]->cfg.primary.image.handle; current_image_valid_= true; current_image_ = addr; - osd_->FlipOnVsync(addr); + osd_->FlipOnVsync(display_configs[0]); } else { current_image_valid_= false; if (full_init_done_) { diff --git a/zircon/system/dev/display/astro-display/osd.cpp b/zircon/system/dev/display/astro-display/osd.cpp index f9a791be7f8b6776a936a7bb6023b613b9e3e603..382b91efea94e8f555d124253dd0d963e6f40a39 100644 --- a/zircon/system/dev/display/astro-display/osd.cpp +++ b/zircon/system/dev/display/astro-display/osd.cpp @@ -9,6 +9,8 @@ #include <ddk/debug.h> #include <ddktl/device.h> #include <fbl/auto_lock.h> +#include <math.h> +#include <float.h> namespace astro_display { @@ -143,7 +145,38 @@ zx_status_t Osd::Configure() { return ZX_OK; } -void Osd::FlipOnVsync(uint8_t idx) { +//TODO(payamm): Vendor spec does not indicate range. However (-1024 1024) seems +// to be the correct range based on experimentation. +uint32_t Osd::FloatToOffset(float f) { + uint32_t offset_val = 0; + if (f < 0) { + offset_val |= (1 << 11); + f *= -1; + } + ZX_DEBUG_ASSERT(0 <= f && f < 1.0f); + + // convert [0 1) --> [0 1024) + f *= 1024; + offset_val |= static_cast<uint32_t>(f); + return offset_val; +} + +//TODO(payamm): Improve performance and accuracy if needed +uint32_t Osd::FloatToFixed3_10(float f) { + uint32_t fixed_num = 0; + if (f < 0) { + f *= -1; + fixed_num |= (1 << 12); + } + fixed_num |= static_cast<uint32_t>((round(f * (1 << 10)))); + fixed_num &= 0x1fff; + return fixed_num; +} + +void Osd::FlipOnVsync(const display_config_t* config) { + + // extract index + uint8_t idx = (uint8_t) config->layer_list[0]->cfg.primary.image.handle; // Get the first available channel int rdma_channel = GetNextAvailableRdmaChannel(); @@ -170,6 +203,67 @@ void Osd::FlipOnVsync(uint8_t idx) { SetRdmaTableValue(rdma_channel, IDX_CFG_W0, cfg_w0); SetRdmaTableValue(rdma_channel, IDX_CTRL_STAT, vpu_mmio_->Read32(VPU_VIU_OSD1_CTRL_STAT) | (1 << 0)); + + // Perform color correction if needed + if (config->cc_flags) { + // Set enable bit + SetRdmaTableValue(rdma_channel, IDX_MATRIX_EN_CTRL, + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_EN_CTRL) | (1 << 0)); + + // Load PreOffset values (or 0 if none entered) + SetRdmaTableValue(rdma_channel, IDX_MATRIX_PRE_OFFSET0_1, + config->cc_flags & COLOR_CONVERSION_PREOFFSET ? + (FloatToOffset(config->cc_preoffsets[0]) << 16 | + FloatToOffset(config->cc_preoffsets[1]) << 0) : 0); + SetRdmaTableValue(rdma_channel, IDX_MATRIX_PRE_OFFSET2, + config->cc_flags & COLOR_CONVERSION_PREOFFSET ? + (FloatToOffset(config->cc_preoffsets[2]) << 0) : 0); + + // Load PostOffset values (or 0 if none entered) + SetRdmaTableValue(rdma_channel, IDX_MATRIX_OFFSET0_1, + config->cc_flags & COLOR_CONVERSION_POSTOFFSET ? + (FloatToOffset(config->cc_postoffsets[0]) << 16 | + FloatToOffset(config->cc_postoffsets[1]) << 0) : 0); + SetRdmaTableValue(rdma_channel, IDX_MATRIX_OFFSET2, + config->cc_flags & COLOR_CONVERSION_POSTOFFSET ? + (FloatToOffset(config->cc_postoffsets[2]) << 0) : 0); + + float identity[3][3] = { + { 1, 0, 0, }, + { 0, 1, 0, }, + { 0, 0, 1, }, + }; + + // This will include either the entered coefficient matrix or the identity matrix + float final[3][3] = {}; + + for (uint32_t i = 0; i < 3; i++) { + for (uint32_t j = 0; j < 3; j++) { + final[i][j] = config->cc_flags & COLOR_CONVERSION_COEFFICIENTS ? + config->cc_coefficients[i][j] : identity[i][j]; + } + } + + // Load up the coefficient matrix registers + SetRdmaTableValue(rdma_channel,IDX_MATRIX_COEF00_01, + FloatToFixed3_10(final[0][0]) << 16 | + FloatToFixed3_10(final[0][1]) << 0); + SetRdmaTableValue(rdma_channel,IDX_MATRIX_COEF02_10, + FloatToFixed3_10(final[0][2]) << 16 | + FloatToFixed3_10(final[1][0]) << 0); + SetRdmaTableValue(rdma_channel,IDX_MATRIX_COEF11_12, + FloatToFixed3_10(final[1][1]) << 16 | + FloatToFixed3_10(final[1][2]) << 0); + SetRdmaTableValue(rdma_channel,IDX_MATRIX_COEF20_21, + FloatToFixed3_10(final[2][0]) << 16 | + FloatToFixed3_10(final[2][1]) << 0); + SetRdmaTableValue(rdma_channel,IDX_MATRIX_COEF22, + FloatToFixed3_10(final[2][2]) << 0); + } else { + // Disable color conversion engine + SetRdmaTableValue(rdma_channel, IDX_MATRIX_EN_CTRL, + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_EN_CTRL) & ~(1 << 0)); + } FlushRdmaTable(rdma_channel); // Write the start and end address of the table. End address is the last address that the @@ -349,6 +443,16 @@ void Osd::ResetRdmaTable() { RdmaTable* rdma_table = reinterpret_cast<RdmaTable*>(rdma_chnl_container_[i].virt_offset); rdma_table[IDX_CFG_W0].reg = (VPU_VIU_OSD1_BLK0_CFG_W0 >> 2); rdma_table[IDX_CTRL_STAT].reg = (VPU_VIU_OSD1_CTRL_STAT >> 2); + rdma_table[IDX_MATRIX_EN_CTRL].reg = (VPU_VPP_POST_MATRIX_EN_CTRL >> 2); + rdma_table[IDX_MATRIX_COEF00_01].reg = (VPU_VPP_POST_MATRIX_COEF00_01 >> 2); + rdma_table[IDX_MATRIX_COEF02_10].reg = (VPU_VPP_POST_MATRIX_COEF02_10 >> 2); + rdma_table[IDX_MATRIX_COEF11_12].reg = (VPU_VPP_POST_MATRIX_COEF11_12 >> 2); + rdma_table[IDX_MATRIX_COEF20_21].reg = (VPU_VPP_POST_MATRIX_COEF20_21 >> 2); + rdma_table[IDX_MATRIX_COEF22].reg = (VPU_VPP_POST_MATRIX_COEF22 >> 2); + rdma_table[IDX_MATRIX_OFFSET0_1].reg = (VPU_VPP_POST_MATRIX_OFFSET0_1 >> 2); + rdma_table[IDX_MATRIX_OFFSET2].reg = (VPU_VPP_POST_MATRIX_OFFSET2 >> 2); + rdma_table[IDX_MATRIX_PRE_OFFSET0_1].reg = (VPU_VPP_POST_MATRIX_PRE_OFFSET0_1 >> 2); + rdma_table[IDX_MATRIX_PRE_OFFSET2].reg = (VPU_VPP_POST_MATRIX_PRE_OFFSET2 >> 2); } } @@ -362,7 +466,7 @@ void Osd::SetRdmaTableValue(uint32_t channel, uint32_t idx, uint32_t val) { void Osd::FlushRdmaTable(uint32_t channel) { zx_status_t status = zx_cache_flush(rdma_chnl_container_[channel].virt_offset, - sizeof(RdmaTable), + IDX_MAX * sizeof(RdmaTable), ZX_CACHE_FLUSH_DATA | ZX_CACHE_FLUSH_INVALIDATE); if (status != ZX_OK) { DISP_ERROR("Could not clean cache %d\n", status); @@ -634,6 +738,28 @@ void Osd::Dump() { vpu_mmio_->Read32(VPU_RDMA_STATUS2)); DISP_INFO("VPU_RDMA_STATUS3 = 0x%x\n", vpu_mmio_->Read32(VPU_RDMA_STATUS3)); + + DISP_INFO("Dumping all Color Correction Matrix related Registers\n\n"); + DISP_INFO("VPU_VPP_POST_MATRIX_COEF00_01 = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF00_01)); + DISP_INFO("VPU_VPP_POST_MATRIX_COEF02_10 = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF02_10)); + DISP_INFO("VPU_VPP_POST_MATRIX_COEF11_12 = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF11_12)); + DISP_INFO("VPU_VPP_POST_MATRIX_COEF20_21 = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF20_21)); + DISP_INFO("VPU_VPP_POST_MATRIX_COEF22 = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_COEF22)); + DISP_INFO("VPU_VPP_POST_MATRIX_OFFSET0_1 = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_OFFSET0_1)); + DISP_INFO("VPU_VPP_POST_MATRIX_OFFSET2 = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_OFFSET2)); + DISP_INFO("VPU_VPP_POST_MATRIX_PRE_OFFSET0_1 = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_PRE_OFFSET0_1)); + DISP_INFO("VPU_VPP_POST_MATRIX_PRE_OFFSET2 = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_PRE_OFFSET2)); + DISP_INFO("VPU_VPP_POST_MATRIX_EN_CTRL = 0x%x\n", + vpu_mmio_->Read32(VPU_VPP_POST_MATRIX_EN_CTRL)); } void Osd::Release() { diff --git a/zircon/system/dev/display/astro-display/osd.h b/zircon/system/dev/display/astro-display/osd.h index 63467a71edfdccbd9456cea7d2d61c04495314a6..eff511d32e775f7d48d4d15efbee08deeb982ada 100644 --- a/zircon/system/dev/display/astro-display/osd.h +++ b/zircon/system/dev/display/astro-display/osd.h @@ -7,6 +7,7 @@ #include <zircon/compiler.h> #include <ddk/protocol/platform/device.h> #include <ddk/protocol/platform-device-lib.h> +#include <ddktl/protocol/display/controller.h> #include <lib/mmio/mmio.h> #include <lib/zx/interrupt.h> #include <lib/zx/bti.h> @@ -25,6 +26,16 @@ struct RdmaTable { enum { IDX_CFG_W0, IDX_CTRL_STAT, + IDX_MATRIX_COEF00_01, + IDX_MATRIX_COEF02_10, + IDX_MATRIX_COEF11_12, + IDX_MATRIX_COEF20_21, + IDX_MATRIX_COEF22, + IDX_MATRIX_OFFSET0_1, + IDX_MATRIX_OFFSET2, + IDX_MATRIX_PRE_OFFSET0_1, + IDX_MATRIX_PRE_OFFSET2, + IDX_MATRIX_EN_CTRL, IDX_MAX, }; @@ -53,7 +64,7 @@ public: zx_status_t Configure(); void Disable(); // This function will apply configuration when VSYNC interrupt occurs using RDMA - void FlipOnVsync(uint8_t idx); + void FlipOnVsync(const display_config_t* config); void Dump(); void Release(); @@ -69,7 +80,9 @@ private: void FlushRdmaTable(uint32_t channel); int GetNextAvailableRdmaChannel(); int RdmaThread(); - + // This function converts a float into Fixed Point 3.10 format + uint32_t FloatToFixed3_10(float f); + uint32_t FloatToOffset(float f); std::optional<ddk::MmioBuffer> vpu_mmio_; pdev_protocol_t pdev_ = {nullptr, nullptr}; zx::bti bti_; diff --git a/zircon/system/dev/display/astro-display/vpu-regs.h b/zircon/system/dev/display/astro-display/vpu-regs.h index 5cdae340022b48b346e617dedc2f0d9ece88b6b7..b5e652bcb394e36ab5e55c9a9c3989eb933be767 100644 --- a/zircon/system/dev/display/astro-display/vpu-regs.h +++ b/zircon/system/dev/display/astro-display/vpu-regs.h @@ -57,4 +57,15 @@ #define VPU_RDARB_MODE_L1C1 (0x2790 << 2) #define VPU_RDARB_MODE_L1C2 (0x2799 << 2) #define VPU_RDARB_MODE_L2C1 (0x279d << 2) -#define VPU_WRARB_MODE_L2C1 (0x27a2 << 2) \ No newline at end of file +#define VPU_WRARB_MODE_L2C1 (0x27a2 << 2) + +#define VPU_VPP_POST_MATRIX_COEF00_01 (0x32b0 << 2) +#define VPU_VPP_POST_MATRIX_COEF02_10 (0x32b1 << 2) +#define VPU_VPP_POST_MATRIX_COEF11_12 (0x32b2 << 2) +#define VPU_VPP_POST_MATRIX_COEF20_21 (0x32b3 << 2) +#define VPU_VPP_POST_MATRIX_COEF22 (0x32b4 << 2) +#define VPU_VPP_POST_MATRIX_OFFSET0_1 (0x32b9 << 2) +#define VPU_VPP_POST_MATRIX_OFFSET2 (0x32ba << 2) +#define VPU_VPP_POST_MATRIX_PRE_OFFSET0_1 (0x32bb << 2) +#define VPU_VPP_POST_MATRIX_PRE_OFFSET2 (0x32bc << 2) +#define VPU_VPP_POST_MATRIX_EN_CTRL (0x32bd << 2) diff --git a/zircon/system/uapp/display-test/main.cpp b/zircon/system/uapp/display-test/main.cpp index d53ddcc4e782a615466af1248bb1e03fa9b4aa21..1be72f672d619fe3668ff9eacb0ff9beeb1abbd7 100644 --- a/zircon/system/uapp/display-test/main.cpp +++ b/zircon/system/uapp/display-test/main.cpp @@ -317,7 +317,12 @@ int main(int argc, const char* argv[]) { fbl::Vector<fbl::Vector<uint64_t>> display_layers; fbl::Vector<fbl::unique_ptr<VirtualLayer>> layers; int32_t num_frames = 120; // default to 120 frames - bool isMediaTek = false; + enum Platform { + INTEL, + ARM_MEDIATEK, + ARM_AMLOGIC, + }; + Platform platform = INTEL; // default to Intel if (!bind_display(&displays)) { return -1; @@ -372,7 +377,11 @@ int main(int argc, const char* argv[]) { argv += 2; argc -= 2; } else if (strcmp(argv[0], "--mediatek") == 0) { - isMediaTek = true; + platform = ARM_MEDIATEK; + argv += 1; + argc -= 1; + } else if (strcmp(argv[0], "--amlogic") == 0) { + platform = ARM_AMLOGIC; argv += 1; argc -= 1; } else { @@ -382,7 +391,7 @@ int main(int argc, const char* argv[]) { } fbl::AllocChecker ac; - if (!isMediaTek) { + if (platform == INTEL) { // Color layer which covers all displays fbl::unique_ptr<ColorLayer> layer0 = fbl::make_unique_checked<ColorLayer>(&ac, displays); if (!ac.check()) { @@ -442,7 +451,7 @@ int main(int argc, const char* argv[]) { CursorLayer* layer4 = new CursorLayer(displays); layers.push_back(std::move(layer4)); #endif - } else { + } else if (platform == ARM_MEDIATEK) { // Mediatek display test uint32_t width = displays[0].mode().horizontal_resolution; uint32_t height = displays[0].mode().vertical_resolution; @@ -487,6 +496,15 @@ int main(int argc, const char* argv[]) { } layer4->SetAlpha(true, (float)0.3); layers.push_back(std::move(layer4)); + } else if (platform == ARM_AMLOGIC) { + // Mediatek display test + fbl::unique_ptr<PrimaryLayer> layer1 = fbl::make_unique_checked<PrimaryLayer>(&ac, + displays); + if (!ac.check()) { + return ZX_ERR_NO_MEMORY; + } + + layers.push_back(std::move(layer1)); } printf("Initializing layers\n");