// 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 "ovl.h" #include "registers-ovl.h" #include #include namespace mt8167s_display { namespace { constexpr uint32_t kDefaultBackgroundColor = 0xFF000000; // alpha/red/green/blue constexpr int kIdleTimeout = 20000; } // namespace zx_status_t Ovl::Init(zx_device_t* parent) { if (initialized_) { return ZX_OK; } zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PDEV, &pdev_); if (status != ZX_OK) { return status; } // Map Ovl mmio mmio_buffer_t mmio; status = pdev_map_mmio_buffer2(&pdev_, MMIO_DISP_OVL, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio); if (status != ZX_OK) { DISP_ERROR("Could not map OVL mmio\n"); return status; } fbl::AllocChecker ac; ovl_mmio_ = fbl::make_unique_checked(&ac, mmio); if (!ac.check()) { DISP_ERROR("Could not mapp Overlay MMIO\n"); return ZX_ERR_NO_MEMORY; } // Get BTI from parent status = pdev_get_bti(&pdev_, 0, bti_.reset_and_get_address()); if (status != ZX_OK) { DISP_ERROR("Could not get BTI handle\n"); return status; } // Ovl is ready to be used initialized_ = true; return ZX_OK; } void Ovl::Reset() { ZX_DEBUG_ASSERT(initialized_); Stop(); active_layers_ = 0; layer_handle_[0] = 0; layer_handle_[1] = 0; layer_handle_[2] = 0; layer_handle_[3] = 0; } bool Ovl::IsSupportedFormat(zx_pixel_format_t format) { if ((format == ZX_PIXEL_FORMAT_RGB_565) || (format == ZX_PIXEL_FORMAT_ARGB_8888) || (format == ZX_PIXEL_FORMAT_RGB_x888)) { return true; } else { return false; } } uint32_t Ovl::GetFormat(zx_pixel_format_t format) { switch (format) { case ZX_PIXEL_FORMAT_RGB_565: return RGB565; case ZX_PIXEL_FORMAT_ARGB_8888: return BGRA8888; case ZX_PIXEL_FORMAT_RGB_x888: return RGB888; } return 0; } bool Ovl::ByteSwapNeeded(zx_pixel_format_t format) { switch (format) { case ZX_PIXEL_FORMAT_ARGB_8888: case ZX_PIXEL_FORMAT_RGB_x888: return false; case ZX_PIXEL_FORMAT_RGB_565: return true; default: ZX_DEBUG_ASSERT(false); } return false; } uint32_t Ovl::GetBytesPerPixel(zx_pixel_format_t format) { switch (format) { case ZX_PIXEL_FORMAT_RGB_565: return 2; case ZX_PIXEL_FORMAT_ARGB_8888: case ZX_PIXEL_FORMAT_RGB_x888: return 4; default: ZX_DEBUG_ASSERT(false); } return 0; } void Ovl::Start() { ZX_DEBUG_ASSERT(initialized_); // Enable the overlay engine and interrupts ovl_mmio_->Write32(INT_FRAME_COMPLETE, OVL_INTEN); ovl_mmio_->Write32(0x1, OVL_EN); ovl_mmio_->ModifyBits32(0x1, 0, 1, OVL_DATAPATH_CON); } void Ovl::Stop() { ZX_DEBUG_ASSERT(initialized_); int timeout = kIdleTimeout; // Disable sources of interrupt and display the overlay engine first ovl_mmio_->Write32(0x0, OVL_INTEN); ovl_mmio_->Write32(0x0, OVL_EN); ovl_mmio_->Write32(0x0, OVL_INTSTA); // Wait for all operations to finish and the state machine is idle while (!IsIdle() && timeout--) { zx_nanosleep(zx_deadline_after(ZX_USEC(1))); } ZX_ASSERT(timeout > 0); // Now that we are idle, we can disable other parts of the engine ovl_mmio_->Write32(0, OVL_DATAPATH_CON); ovl_mmio_->Write32(0, OVL_RDMAx_CTRL(0)); ovl_mmio_->Write32(0, OVL_RDMAx_CTRL(1)); ovl_mmio_->Write32(0, OVL_RDMAx_CTRL(2)); ovl_mmio_->Write32(0, OVL_RDMAx_CTRL(3)); ovl_mmio_->Write32(0, OVL_SRC_CON); } zx_status_t Ovl::Config(uint8_t layer, OvlConfig &cfg) { ZX_DEBUG_ASSERT(initialized_); ZX_DEBUG_ASSERT(layer < kMaxLayer); // Configure ROI first. ROI abbreviation is not clarified in docs. Assuming it means // Region Of Interest. Also, ROI does not seem to be "layer" related. So it might mean the // final screen after all the layers have been mixed. ovl_mmio_->Write32(height_ << 16 | width_, OVL_ROI_SIZE); ovl_mmio_->Write32(kDefaultBackgroundColor,OVL_ROI_BGCLR); // Enable Layer // We cannot simply enable a layer and/or its RDMA channel source. This could // only be done at IDLE time. Config should only be called after calling the stop function // which places the engine in Idle. if (IsIdle()) { ovl_mmio_->Write32(ovl_mmio_->Read32(OVL_SRC_CON) | SRC_CON_ENABLE_LAYER(layer), OVL_SRC_CON); ovl_mmio_->ModifyBits32(1, 0, 1, OVL_RDMAx_CTRL(layer)); } else { // We are not Idle! Let's dump all registers and crash Dump(); ZX_ASSERT(false); } // Make sure we support the input format if (!IsSupportedFormat(cfg.format)) { DISP_ERROR("Unsupported format: 0x%x\n", cfg.format); ZX_ASSERT(false); } // Setup various OVL CON register uint32_t regVal = 0; if (cfg.alpha_mode != ALPHA_DISABLE) { regVal = Lx_CON_AEN; // enable alpha blending if (!isnan(cfg.alpha_val)) { // Apply alpha value regVal |= Lx_CON_ALPHA(static_cast(round(cfg.alpha_val * 255))); } else { // Enable per-pixel only, therefore set multiplier to 1 regVal |= Lx_CON_ALPHA(0xFF); } } if (ByteSwapNeeded(cfg.format)) { regVal |= Lx_CON_BYTE_SWAP; } regVal |= Lx_CON_CLRFMT(GetFormat(cfg.format)); ovl_mmio_->Write32(regVal, OVL_Lx_CON(layer)); // write the height and width of source buffer for this layer ovl_mmio_->Write32(height_ << 16 | width_, OVL_Lx_SRC_SIZE(layer)); // set the offset of actual image within the buffer ovl_mmio_->Write32(y_ << 16 | x_, OVL_Lx_OFFSET(layer)); // set the physical address of the buffer for this layer uint32_t finaladdr = static_cast(cfg.paddr) + x_ * GetBytesPerPixel(cfg.format) + y_ * pitch_; ovl_mmio_->Write32(finaladdr, OVL_Lx_ADDR(layer)); // setup Lx_PITCH_PITCH register regVal = 0; regVal |= Lx_PITCH_PITCH(pitch_); ovl_mmio_->Write32(regVal, OVL_Lx_PITCH(layer)); // Setup magical register with undocumented magic value ovl_mmio_->Write32(0x6070, OVL_RDMAx_MEM_GMC_SETTING(layer)); active_layers_ |= static_cast((1 << layer)); layer_handle_[layer] = cfg.paddr; return ZX_OK; } void Ovl::Dump() { zxlogf(INFO, "Dumping OVL Registers:\n"); zxlogf(INFO, "######################\n\n"); zxlogf(INFO, "OVL_STA = 0x%x\n", ovl_mmio_->Read32(OVL_STA)); zxlogf(INFO, "OVL_INTEN = 0x%x\n", ovl_mmio_->Read32(OVL_INTEN)); zxlogf(INFO, "OVL_INTSTA = 0x%x\n", ovl_mmio_->Read32(OVL_INTSTA)); zxlogf(INFO, "OVL_EN = 0x%x\n", ovl_mmio_->Read32(OVL_EN)); zxlogf(INFO, "OVL_TRIG = 0x%x\n", ovl_mmio_->Read32(OVL_TRIG)); zxlogf(INFO, "OVL_RST = 0x%x\n", ovl_mmio_->Read32(OVL_RST)); zxlogf(INFO, "OVL_ROI_SIZE = 0x%x\n", ovl_mmio_->Read32(OVL_ROI_SIZE)); zxlogf(INFO, "OVL_DATAPATH_CON = 0x%x\n", ovl_mmio_->Read32(OVL_DATAPATH_CON)); zxlogf(INFO, "OVL_ROI_BGCLR = 0x%x\n", ovl_mmio_->Read32(OVL_ROI_BGCLR)); zxlogf(INFO, "OVL_SRC_CON = 0x%x\n", ovl_mmio_->Read32(OVL_SRC_CON)); zxlogf(INFO, "OVL_Lx_CON0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_CON(0)), ovl_mmio_->Read32(OVL_Lx_CON(1)), ovl_mmio_->Read32(OVL_Lx_CON(2)), ovl_mmio_->Read32(OVL_Lx_CON(3))); zxlogf(INFO, "OVL_Lx_SRCKEY0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_SRCKEY(0)), ovl_mmio_->Read32(OVL_Lx_SRCKEY(1)), ovl_mmio_->Read32(OVL_Lx_SRCKEY(2)), ovl_mmio_->Read32(OVL_Lx_SRCKEY(3))); zxlogf(INFO, "OVL_Lx_SRC_SIZE0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_SRC_SIZE(0)), ovl_mmio_->Read32(OVL_Lx_SRC_SIZE(1)), ovl_mmio_->Read32(OVL_Lx_SRC_SIZE(2)), ovl_mmio_->Read32(OVL_Lx_SRC_SIZE(3))); zxlogf(INFO, "OVL_Lx_OFFSET0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_OFFSET(0)), ovl_mmio_->Read32(OVL_Lx_OFFSET(1)), ovl_mmio_->Read32(OVL_Lx_OFFSET(2)), ovl_mmio_->Read32(OVL_Lx_OFFSET(3))); zxlogf(INFO, "OVL_Lx_ADDR0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_ADDR(0)), ovl_mmio_->Read32(OVL_Lx_ADDR(1)), ovl_mmio_->Read32(OVL_Lx_ADDR(2)), ovl_mmio_->Read32(OVL_Lx_ADDR(3))); zxlogf(INFO, "OVL_Lx_PITCH0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_PITCH(0)), ovl_mmio_->Read32(OVL_Lx_PITCH(1)), ovl_mmio_->Read32(OVL_Lx_PITCH(2)), ovl_mmio_->Read32(OVL_Lx_PITCH(3))); zxlogf(INFO, "OVL_Lx_TILE0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_TILE(0)), ovl_mmio_->Read32(OVL_Lx_TILE(1)), ovl_mmio_->Read32(OVL_Lx_TILE(2)), ovl_mmio_->Read32(OVL_Lx_TILE(3))); zxlogf(INFO, "OVL_RDMAx_CTRL0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_RDMAx_CTRL(0)), ovl_mmio_->Read32(OVL_RDMAx_CTRL(1)), ovl_mmio_->Read32(OVL_RDMAx_CTRL(2)), ovl_mmio_->Read32(OVL_RDMAx_CTRL(3))); zxlogf(INFO, "OVL_RDMAx_MEM_GMC_SETTING0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_RDMAx_MEM_GMC_SETTING(0)), ovl_mmio_->Read32(OVL_RDMAx_MEM_GMC_SETTING(1)), ovl_mmio_->Read32(OVL_RDMAx_MEM_GMC_SETTING(2)), ovl_mmio_->Read32(OVL_RDMAx_MEM_GMC_SETTING(3))); zxlogf(INFO, "OVL_RDMAx_MEM_SLOW_CON0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_RDMAx_MEM_SLOW_CON(0)), ovl_mmio_->Read32(OVL_RDMAx_MEM_SLOW_CON(1)), ovl_mmio_->Read32(OVL_RDMAx_MEM_SLOW_CON(2)), ovl_mmio_->Read32(OVL_RDMAx_MEM_SLOW_CON(3))); zxlogf(INFO, "OVL_RDMAx_FIFO_CTRL0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_RDMAx_FIFO_CTRL(0)), ovl_mmio_->Read32(OVL_RDMAx_FIFO_CTRL(1)), ovl_mmio_->Read32(OVL_RDMAx_FIFO_CTRL(2)), ovl_mmio_->Read32(OVL_RDMAx_FIFO_CTRL(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_R00123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_R0(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_R0(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_R0(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_R0(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_R10123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_R1(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_R1(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_R1(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_R1(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_G00123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_G0(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_G0(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_G0(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_G0(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_G10123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_G1(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_G1(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_G1(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_G1(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_B00123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_B0(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_B0(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_B0(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_B0(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_B10123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_B1(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_B1(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_B1(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_B1(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_YUV_A_00123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_YUV_A_0(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_YUV_A_0(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_YUV_A_0(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_YUV_A_0(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_YUV_A_10123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_YUV_A_1(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_YUV_A_1(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_YUV_A_1(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_YUV_A_1(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_RGB_A_00123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_RGB_A_0(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_RGB_A_0(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_RGB_A_0(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_RGB_A_0(3))); zxlogf(INFO, "OVL_Lx_Y2R_PARA_RGB_A_10123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_RGB_A_1(0)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_RGB_A_1(1)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_RGB_A_1(2)), ovl_mmio_->Read32(OVL_Lx_Y2R_PARA_RGB_A_1(3))); zxlogf(INFO, "OVL_DEBUG_MON_SEL = 0x%x\n", ovl_mmio_->Read32(OVL_DEBUG_MON_SEL)); zxlogf(INFO, "OVL_RDMAx_MEM_GMC_S20123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_RDMAx_MEM_GMC_S2(0)), ovl_mmio_->Read32(OVL_RDMAx_MEM_GMC_S2(1)), ovl_mmio_->Read32(OVL_RDMAx_MEM_GMC_S2(2)), ovl_mmio_->Read32(OVL_RDMAx_MEM_GMC_S2(3))); zxlogf(INFO, "OVL_DUMMY_REG = 0x%x\n", ovl_mmio_->Read32(OVL_DUMMY_REG)); zxlogf(INFO, "OVL_SMI_DBG = 0x%x\n", ovl_mmio_->Read32(OVL_SMI_DBG)); zxlogf(INFO, "OVL_GREQ_LAYER_CNT = 0x%x\n", ovl_mmio_->Read32(OVL_GREQ_LAYER_CNT)); zxlogf(INFO, "OVL_FLOW_CTRL_DBG = 0x%x\n", ovl_mmio_->Read32(OVL_FLOW_CTRL_DBG)); zxlogf(INFO, "OVL_ADDCON_DBG = 0x%x\n", ovl_mmio_->Read32(OVL_ADDCON_DBG)); zxlogf(INFO, "OVL_RDMAx_DBG0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_RDMAx_DBG(0)), ovl_mmio_->Read32(OVL_RDMAx_DBG(1)), ovl_mmio_->Read32(OVL_RDMAx_DBG(2)), ovl_mmio_->Read32(OVL_RDMAx_DBG(3))); zxlogf(INFO, "OVL_Lx_CLR0123 = 0x%x, 0x%x, 0x%x, 0x%x\n", ovl_mmio_->Read32(OVL_Lx_CLR(0)), ovl_mmio_->Read32(OVL_Lx_CLR(1)), ovl_mmio_->Read32(OVL_Lx_CLR(2)), ovl_mmio_->Read32(OVL_Lx_CLR(3))); zxlogf(INFO, "######################\n\n"); } } //namespace mt8167s_display