zx_status_t Osd::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 vpu mmio used by the OSD object mmio_buffer_t mmio; status = pdev_map_mmio_buffer(&pdev_, MMIO_VPU, ZX_CACHE_POLICY_UNCACHED_DEVICE, &mmio); if (status != ZX_OK) { DISP_ERROR("osd: Could not map VPU mmio\n"); return status; } vpu_mmio_ = ddk::MmioBuffer(mmio); // 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; } //Map RDMA Done Interrupt status = pdev_map_interrupt(&pdev_, IRQ_RDMA, rdma_irq_.reset_and_get_address()); if (status != ZX_OK) { DISP_ERROR("Could not map RDMA interrupt\n"); return status; } auto start_thread = [](void* arg) {return static_cast<Osd*>(arg)->RdmaThread(); }; status = thrd_create_with_name(&rdma_thread_, start_thread, this, "rdma_thread"); if (status != ZX_OK) { DISP_ERROR("Could not create rdma_thread\n"); return status; } // Setup RDMA status = SetupRdma(); if (status != ZX_OK) { DISP_ERROR("Could not setup RDMA\n"); return status; } // OSD object is ready to be used. initialized_ = true; return ZX_OK; }
zx_status_t Osd::SetupRdma() { zx_status_t status = ZX_OK; DISP_INFO("Setting up RDMA\n"); // since we are flushing the caches, make sure the tables are at least cache_line apart ZX_DEBUG_ASSERT(kChannelBaseOffset > zx_system_get_dcache_line_size()); // Allocate one page for RDMA Table status = zx_vmo_create_contiguous(bti_.get(), ZX_PAGE_SIZE, 0, rdma_vmo_.reset_and_get_address()); if (status != ZX_OK) { DISP_ERROR("Could not create RDMA VMO (%d)\n", status); return status; } status = zx_bti_pin(bti_.get(), ZX_BTI_PERM_READ | ZX_BTI_PERM_WRITE, rdma_vmo_.get(), 0, ZX_PAGE_SIZE, &rdma_phys_, 1, &rdma_pmt_); if (status != ZX_OK) { DISP_ERROR("Could not pin RDMA VMO (%d)\n", status); return status; } status = zx_vmar_map(zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, rdma_vmo_.get(), 0, ZX_PAGE_SIZE, reinterpret_cast<zx_vaddr_t*>(&rdma_vbuf_)); if (status != ZX_OK) { DISP_ERROR("Could not map vmar (%d)\n", status); return status; } // Initialize each rdma channel container for (int i = 0; i < kMaxRdmaChannels; i++) { ZX_DEBUG_ASSERT((i * kChannelBaseOffset) < ZX_PAGE_SIZE); rdma_chnl_container_[i].phys_offset = rdma_phys_ + (i * kChannelBaseOffset); rdma_chnl_container_[i].virt_offset = rdma_vbuf_ + (i * kChannelBaseOffset); rdma_chnl_container_[i].active = false; } // Setup RDMA_CTRL: // Default: no reset, no clock gating, burst size 4x16B for read and write // DDR Read/Write request urgent uint32_t regVal = RDMA_CTRL_READ_URGENT | RDMA_CTRL_WRITE_URGENT; vpu_mmio_->Write32(regVal, VPU_RDMA_CTRL); ResetRdmaTable(); return status; }
HI_S32 DISP_UA_Init(HI_DRV_DISP_VERSION_S *pstVersion) { HI_S32 nRet; if (!pstVersion) { DISP_ERROR("FUNC(%s) Error! Invalid input parameters!\n", __FUNCTION__); return HI_FAILURE; } if (g_bUAInitFlag) { DISP_INFO("FUNC(%s) inited!\n", __FUNCTION__); return HI_SUCCESS; } DISP_MEMSET(&g_stUAFuntion, 0, sizeof(g_stUAFuntion)); if ( (pstVersion->u32VersionPartH == DISP_CV200_ES_VERSION_H) && (pstVersion->u32VersionPartL == DISP_CV200_ES_VERSION_L) ) { // 准备工作,包括资源申请 nRet = ALG_VZmeVdpComnInit(&g_stVZMEInstance); if (nRet) { DISP_ERROR("ALG_VZmeVdpComnInit failed!\n"); return HI_FAILURE; } // 函数指针赋值 g_stUAFuntion.pfCalcCscCoef = DISP_ALG_CscCoefSet; g_stUAFuntion.pfVZmeVdpHQSet = UA_VZmeVdpHQSet; g_stUAFuntion.pfVZmeVdpSQSet = UA_VZmeVdpSQSet; g_stUAFuntion.pfVZmeVdpSQSetSeperateAddr = UA_VZmeVdpSQSetSeparateAddr; } else { DISP_ERROR("FUNC(%s) Error! Invalid display version!", __FUNCTION__); return HI_FAILURE; } g_bUAInitFlag = HI_TRUE; return HI_SUCCESS; }
HI_S32 DispBuf_GetFullNodeNumber(DISP_BUF_S *pstBuffer, HI_U32 *pu32Num) { HI_U32 num; HI_U32 r, w; DBC_CHECK_NULL_RETURN(pstBuffer); DBC_CHECK_NULL_RETURN(pu32Num); r = pstBuffer->u32FullReaddPos; w = pstBuffer->u32FullWritePos; if (w >= r) { num = w - r; } else { num = w + pstBuffer->u32Number- r; } if (num <= pstBuffer->u32Number) { *pu32Num = num; } else { DISP_ERROR("DispBuf_GetFullNodeNumber invalid!\n"); *pu32Num = 0; } return HI_SUCCESS; }
void Osd::FlushRdmaTable(uint32_t channel) { zx_status_t status = zx_cache_flush(rdma_chnl_container_[channel].virt_offset, sizeof(RdmaTable), ZX_CACHE_FLUSH_DATA | ZX_CACHE_FLUSH_INVALIDATE); if (status != ZX_OK) { DISP_ERROR("Could not clean cache %d\n", status); return; } }
HI_S32 DispBuf_Create(DISP_BUF_S *pstBuffer, HI_U32 number) { DISP_BUF_NODE_S *pstNewNode; HI_U32 u; if (!number || (number > DISP_BUF_NODE_MAX_NUMBER)) { DISP_ERROR("DispBuf_Create buffer number is invalid %d\n", number); return HI_FAILURE; } DISP_MEMSET(pstBuffer, 0, sizeof(DISP_BUF_S)); pstBuffer->u32BufID = (s_u32BufIDCount++) & 0xffffUL; pstBuffer->u32Number = number; for(u=0; u<pstBuffer->u32Number; u++) { pstNewNode = (DISP_BUF_NODE_S *)DISP_MALLOC(sizeof(DISP_BUF_NODE_S)); if (!pstNewNode) { DISP_ERROR("DispBuf_Create malloc node memory!\n"); goto __ERR_RELEASE__; } pstBuffer->pstBufArray[u] = pstNewNode; } DispBuf_Reset(pstBuffer); return HI_SUCCESS; __ERR_RELEASE__: for(; u>0; u--) { DISP_FREE(pstBuffer->pstBufArray[u-1]); } return HI_FAILURE; }
HI_S32 DISP_DA_Init(HI_DRV_DISP_VERSION_S *pstVersion) { //HI_S32 nRet; if (!pstVersion) { DISP_ERROR("FUNC(%s) Error! Invalid input parameters!\n", __FUNCTION__); return HI_FAILURE; } if (g_bDAInitFlag) { DISP_INFO("FUNC(%s) inited!\n", __FUNCTION__); return HI_SUCCESS; } DISP_MEMSET(&g_stDAFuntion, 0, sizeof(g_stDAFuntion)); if ( (pstVersion->u32VersionPartH == DISP_CV200_ES_VERSION_H) && (pstVersion->u32VersionPartL == DISP_CV200_ES_VERSION_L) ) { // º¯ÊýÖ¸Õ븳ֵ g_stDAFuntion.PFCscRgb2Yuv = DISP_ALG_CscRgb2Yuv; g_stDAFuntion.pfCalcCscCoef = DISP_ALG_CscCoefSet; } else { DISP_ERROR("FUNC(%s) Error! Invalid display version!", __FUNCTION__); return HI_FAILURE; } g_bDAInitFlag = HI_TRUE; return HI_SUCCESS; }
zx_status_t get_vic(const display_mode_t* disp_timing, struct hdmi_param* p) { // Monitor has its own preferred timings. Use that p->timings.interlace_mode = disp_timing->flags & MODE_FLAG_INTERLACED; p->timings.pfreq = (disp_timing->pixel_clock_10khz * 10); // KHz //TODO: pixel repetition is 0 for most progressive. We don't support interlaced p->timings.pixel_repeat = 0; p->timings.hactive = disp_timing->h_addressable; p->timings.hblank = disp_timing->h_blanking; p->timings.hfront = disp_timing->h_front_porch; p->timings.hsync = disp_timing->h_sync_pulse; p->timings.htotal = (p->timings.hactive) + (p->timings.hblank); p->timings.hback = (p->timings.hblank) - (p->timings.hfront + p->timings.hsync); p->timings.hpol = disp_timing->flags & MODE_FLAG_HSYNC_POSITIVE; p->timings.vactive = disp_timing->v_addressable; p->timings.vblank0 = disp_timing->v_blanking; p->timings.vfront = disp_timing->v_front_porch; p->timings.vsync = disp_timing->v_sync_pulse; p->timings.vtotal = (p->timings.vactive) + (p->timings.vblank0); p->timings.vback = (p->timings.vblank0) - (p->timings.vfront + p->timings.vsync); p->timings.vpol = disp_timing->flags & MODE_FLAG_VSYNC_POSITIVE; //FIXE: VENC Repeat is undocumented. It seems to be only needed for the following // resolutions: 1280x720p60, 1280x720p50, 720x480p60, 720x480i60, 720x576p50, 720x576i50 // For now, we will simply not support this feature. p->timings.venc_pixel_repeat = 0; // Let's make sure we support what we've got so far if (p->timings.interlace_mode) { return ZX_ERR_NOT_SUPPORTED; } if (p->timings.vactive == 2160) { DISP_INFO("4K Monitor Detected.\n"); if (p->timings.pfreq == 533250) { // FIXME: 4K with reduced blanking (533.25MHz) does not work DISP_INFO("4K @ 30Hz\n"); p->timings.interlace_mode = 0; p->timings.pfreq = (297000); // KHz p->timings.pixel_repeat = 0; p->timings.hactive = 3840; p->timings.hblank = 560; p->timings.hfront = 176; p->timings.hsync = 88; p->timings.htotal = (p->timings.hactive) + (p->timings.hblank); p->timings.hback = (p->timings.hblank) - (p->timings.hfront + p->timings.hsync); p->timings.hpol = 1; p->timings.vactive = 2160; p->timings.vblank0 = 90; p->timings.vfront = 8; p->timings.vsync = 10; p->timings.vtotal = (p->timings.vactive) + (p->timings.vblank0); p->timings.vback = (p->timings.vblank0) - (p->timings.vfront + p->timings.vsync); p->timings.vpol = 1; } } if (p->timings.pfreq > 500000) { p->is4K = true; } else { p->is4K = false; } if (p->timings.hactive * 3 == p->timings.vactive * 4) { p->aspect_ratio = HDMI_ASPECT_RATIO_4x3; } else if (p->timings.hactive * 9 == p->timings.vactive * 16) { p->aspect_ratio = HDMI_ASPECT_RATIO_16x9; } else { p->aspect_ratio = HDMI_ASPECT_RATIO_NONE; } p->colorimetry = HDMI_COLORIMETRY_ITU601; if (p->timings.pfreq > 500000) { p->phy_mode = 1; } else if (p->timings.pfreq > 200000) { p->phy_mode = 2; } else if (p->timings.pfreq > 100000) { p->phy_mode = 3; } else { p->phy_mode = 4; } //TODO: We probably need a more sophisticated method for calculating // clocks. This will do for now. p->pll_p_24b.viu_channel = 1; p->pll_p_24b.viu_type = VIU_ENCP; p->pll_p_24b.vid_pll_div = VID_PLL_DIV_5; p->pll_p_24b.vid_clk_div = 2; p->pll_p_24b.hdmi_tx_pixel_div = 1; p->pll_p_24b.encp_div = 1; p->pll_p_24b.od1 = 1; p->pll_p_24b.od2 = 1; p->pll_p_24b.od3 = 1; p->pll_p_24b.hpll_clk_out = (p->timings.pfreq * 10); while (p->pll_p_24b.hpll_clk_out < 2900000) { if (p->pll_p_24b.od1 < 4) { p->pll_p_24b.od1 *= 2; p->pll_p_24b.hpll_clk_out *= 2; } else if (p->pll_p_24b.od2 < 4) { p->pll_p_24b.od2 *= 2; p->pll_p_24b.hpll_clk_out *= 2; } else if (p->pll_p_24b.od3 < 4) { p->pll_p_24b.od3 *= 2; p->pll_p_24b.hpll_clk_out *= 2; } else { return ZX_ERR_OUT_OF_RANGE; } } if(p->pll_p_24b.hpll_clk_out > 6000000) { DISP_ERROR("Something went wrong in clock calculation (pll_out = %d)\n", p->pll_p_24b.hpll_clk_out); return ZX_ERR_OUT_OF_RANGE; } return ZX_OK; }