/* * This function enables a logical channel. * * @param channel Input parameter for the logical channel ID. * * @return This function returns 0 on success or negative error code on * fail. */ int32_t ipu_enable_channel(ipu_channel_t channel) { uint32_t reg; uint32_t in_dma; uint32_t out_dma; if (g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) { printf("Warning: channel already enabled %d\n", IPU_CHAN_ID(channel)); } /* Get input and output dma channels */ out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); if (idma_is_valid(in_dma)) { reg = __raw_readl(IDMAC_CHA_EN(in_dma)); __raw_writel(reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma)); } if (idma_is_valid(out_dma)) { reg = __raw_readl(IDMAC_CHA_EN(out_dma)); __raw_writel(reg | idma_mask(out_dma), IDMAC_CHA_EN(out_dma)); } if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC)) ipu_dp_dc_enable(channel); g_channel_enable_mask |= 1L << IPU_CHAN_ID(channel); return 0; }
/* * This function disables a logical channel. * * @param channel Input parameter for the logical channel ID. * * @param wait_for_stop Flag to set whether to wait for channel end * of frame or return immediately. * * @return This function returns 0 on success or negative error code on * fail. */ int32_t ipu_disable_channel(ipu_channel_t channel) { uint32_t reg; uint32_t in_dma; uint32_t out_dma; if ((g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) { debug("Channel already disabled %d\n", IPU_CHAN_ID(channel)); return 0; } /* Get input and output dma channels */ out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); if ((idma_is_valid(in_dma) && !idma_is_set(IDMAC_CHA_EN, in_dma)) && (idma_is_valid(out_dma) && !idma_is_set(IDMAC_CHA_EN, out_dma))) return -EINVAL; if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) || (channel == MEM_DC_SYNC)) { ipu_dp_dc_disable(channel, 0); } /* Disable DMA channel(s) */ if (idma_is_valid(in_dma)) { reg = __raw_readl(IDMAC_CHA_EN(in_dma)); __raw_writel(reg & ~idma_mask(in_dma), IDMAC_CHA_EN(in_dma)); __raw_writel(idma_mask(in_dma), IPU_CHA_CUR_BUF(in_dma)); } if (idma_is_valid(out_dma)) { reg = __raw_readl(IDMAC_CHA_EN(out_dma)); __raw_writel(reg & ~idma_mask(out_dma), IDMAC_CHA_EN(out_dma)); __raw_writel(idma_mask(out_dma), IPU_CHA_CUR_BUF(out_dma)); } g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel)); /* Set channel buffers NOT to be ready */ if (idma_is_valid(in_dma)) { ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0); ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 1); } if (idma_is_valid(out_dma)) { ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 0); ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 1); } return 0; }
/* * This function is called to uninitialize a logical IPU channel. * * @param channel Input parameter for the logical channel ID to uninit. */ void ipu_uninit_channel(ipu_channel_t channel) { uint32_t reg; uint32_t in_dma, out_dma = 0; uint32_t ipu_conf; if ((g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) { debug("Channel already uninitialized %d\n", IPU_CHAN_ID(channel)); return; } /* * Make sure channel is disabled * Get input and output dma channels */ in_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER); out_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER); if (idma_is_set(IDMAC_CHA_EN, in_dma) || idma_is_set(IDMAC_CHA_EN, out_dma)) { printf( "Channel %d is not disabled, disable first\n", IPU_CHAN_ID(channel)); return; } ipu_conf = __raw_readl(IPU_CONF); /* Reset the double buffer */ reg = __raw_readl(IPU_CHA_DB_MODE_SEL(in_dma)); __raw_writel(reg & ~idma_mask(in_dma), IPU_CHA_DB_MODE_SEL(in_dma)); reg = __raw_readl(IPU_CHA_DB_MODE_SEL(out_dma)); __raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma)); switch (channel) { case MEM_DC_SYNC: ipu_dc_uninit(1); ipu_di_use_count[g_dc_di_assignment[1]]--; ipu_dc_use_count--; ipu_dmfc_use_count--; break; case MEM_BG_SYNC: ipu_dp_uninit(channel); ipu_dc_uninit(5); ipu_di_use_count[g_dc_di_assignment[5]]--; ipu_dc_use_count--; ipu_dp_use_count--; ipu_dmfc_use_count--; break; case MEM_FG_SYNC: ipu_dp_uninit(channel); ipu_dc_use_count--; ipu_dp_use_count--; ipu_dmfc_use_count--; break; default: break; } g_channel_init_mask &= ~(1L << IPU_CHAN_ID(channel)); if (ipu_dc_use_count == 0) ipu_conf &= ~IPU_CONF_DC_EN; if (ipu_dp_use_count == 0) ipu_conf &= ~IPU_CONF_DP_EN; if (ipu_dmfc_use_count == 0) ipu_conf &= ~IPU_CONF_DMFC_EN; if (ipu_di_use_count[0] == 0) { ipu_conf &= ~IPU_CONF_DI0_EN; } if (ipu_di_use_count[1] == 0) { ipu_conf &= ~IPU_CONF_DI1_EN; } __raw_writel(ipu_conf, IPU_CONF); if (ipu_conf == 0) { clk_disable(g_ipu_clk); g_ipu_clk_enabled = 0; } }
/* * This function is called to initialize a logical IPU channel. * * @param channel Input parameter for the logical channel ID to init. * * @param params Input parameter containing union of channel * initialization parameters. * * @return Returns 0 on success or negative error code on fail */ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) { int ret = 0; uint32_t ipu_conf; debug("init channel = %d\n", IPU_CHAN_ID(channel)); if (g_ipu_clk_enabled == 0) { g_ipu_clk_enabled = 1; clk_enable(g_ipu_clk); } if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) { printf("Warning: channel already initialized %d\n", IPU_CHAN_ID(channel)); } ipu_conf = __raw_readl(IPU_CONF); switch (channel) { case MEM_DC_SYNC: if (params->mem_dc_sync.di > 1) { ret = -EINVAL; goto err; } g_dc_di_assignment[1] = params->mem_dc_sync.di; ipu_dc_init(1, params->mem_dc_sync.di, params->mem_dc_sync.interlaced); ipu_di_use_count[params->mem_dc_sync.di]++; ipu_dc_use_count++; ipu_dmfc_use_count++; break; case MEM_BG_SYNC: if (params->mem_dp_bg_sync.di > 1) { ret = -EINVAL; goto err; } g_dc_di_assignment[5] = params->mem_dp_bg_sync.di; ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt, params->mem_dp_bg_sync.out_pixel_fmt); ipu_dc_init(5, params->mem_dp_bg_sync.di, params->mem_dp_bg_sync.interlaced); ipu_di_use_count[params->mem_dp_bg_sync.di]++; ipu_dc_use_count++; ipu_dp_use_count++; ipu_dmfc_use_count++; break; case MEM_FG_SYNC: ipu_dp_init(channel, params->mem_dp_fg_sync.in_pixel_fmt, params->mem_dp_fg_sync.out_pixel_fmt); ipu_dc_use_count++; ipu_dp_use_count++; ipu_dmfc_use_count++; break; default: printf("Missing channel initialization\n"); break; } /* Enable IPU sub module */ g_channel_init_mask |= 1L << IPU_CHAN_ID(channel); if (ipu_dc_use_count == 1) ipu_conf |= IPU_CONF_DC_EN; if (ipu_dp_use_count == 1) ipu_conf |= IPU_CONF_DP_EN; if (ipu_dmfc_use_count == 1) ipu_conf |= IPU_CONF_DMFC_EN; if (ipu_di_use_count[0] == 1) { ipu_conf |= IPU_CONF_DI0_EN; } if (ipu_di_use_count[1] == 1) { ipu_conf |= IPU_CONF_DI1_EN; } __raw_writel(ipu_conf, IPU_CONF); err: return ret; }
/* * This function is called to initialize a logical IPU channel. * * @param channel Input parameter for the logical channel ID to init. * * @param params Input parameter containing union of channel * initialization parameters. * * @return Returns 0 on success or negative error code on fail */ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params) { int ret = 0; uint32_t ipu_conf; u32 reg; debug("init channel = %d\n", IPU_CHAN_ID(channel)); if (g_ipu_clk_enabled == 0) { g_ipu_clk_enabled = 1; clk_enable(g_ipu_clk); } if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) { printf("Warning--0: channel already initialized %d\n", IPU_CHAN_ID(channel)); } ipu_conf = __raw_readl(IPU_CONF); switch (channel) { case CSI_MEM: if (params->csi_mem.csi > 1) { ret = -EINVAL; goto err; } //printf("csi_mem interlaced= %d, csi_mem mipi_en: %d\n", params->csi_mem.interlaced, params->csi_mem.mipi_en); if (params->csi_mem.interlaced) g_chan_is_interlaced[channel_2_dma(channel, IPU_OUTPUT_BUFFER)] = 0x1; else g_chan_is_interlaced[channel_2_dma(channel, IPU_OUTPUT_BUFFER)] = 0x0; ipu_smfc_use_count++; g_ipu_csi_channel[params->csi_mem.csi] = channel; /*SMFC setting*/ if (params->csi_mem.mipi_en) { ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + params->csi_mem.csi)); _ipu_smfc_init(channel, params->csi_mem.mipi_id, params->csi_mem.csi); } else { ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + params->csi_mem.csi)); _ipu_smfc_init(channel, 0, params->csi_mem.csi); } /*CSI data (include compander) dest*/ _ipu_csi_init(channel, params->csi_mem.csi); break; case CSI_PRP_ENC_MEM: if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) { printf("Warning--1: channel already initialized %d\n", IPU_CHAN_ID(channel)); /*CSI data (include compander) dest*/ _ipu_csi_init(channel, params->csi_prp_enc_mem.csi); }else{ if (params->csi_prp_enc_mem.csi > 1) { ret = -EINVAL; goto err; } using_ic_dirct_ch = CSI_PRP_ENC_MEM; ipu_ic_use_count++; g_ipu_csi_channel[params->csi_prp_enc_mem.csi] = channel; /*Without SMFC, CSI only support parallel data source*/ ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + params->csi_prp_enc_mem.csi)); /*CSI0/1 feed into IC*/ ipu_conf &= ~IPU_CONF_IC_INPUT; if (params->csi_prp_enc_mem.csi) ipu_conf |= IPU_CONF_CSI_SEL; else ipu_conf &= ~IPU_CONF_CSI_SEL; /*PRP skip buffer in memory, only valid when RWS_EN is true*/ reg = __raw_readl(IPU_FS_PROC_FLOW1); __raw_writel(reg & ~FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1); /*CSI data (include compander) dest*/ _ipu_csi_init(channel, params->csi_prp_enc_mem.csi); _ipu_ic_init_prpenc(params, 1); } break; case CSI_PRP_VF_MEM: if (params->csi_prp_vf_mem.csi > 1) { ret = -EINVAL; goto err; } using_ic_dirct_ch = CSI_PRP_VF_MEM; ipu_ic_use_count++; g_ipu_csi_channel[params->csi_prp_vf_mem.csi] = channel; /*Without SMFC, CSI only support parallel data source*/ ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + params->csi_prp_vf_mem.csi)); /*CSI0/1 feed into IC*/ ipu_conf &= ~IPU_CONF_IC_INPUT; if (params->csi_prp_vf_mem.csi) ipu_conf |= IPU_CONF_CSI_SEL; else ipu_conf &= ~IPU_CONF_CSI_SEL; /*PRP skip buffer in memory, only valid when RWS_EN is true*/ reg = __raw_readl(IPU_FS_PROC_FLOW1); __raw_writel(reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1); /*CSI data (include compander) dest*/ _ipu_csi_init(channel, params->csi_prp_vf_mem.csi); _ipu_ic_init_prpvf(params, 1); break; case MEM_DC_SYNC: if (params->mem_dc_sync.di > 1) { ret = -EINVAL; goto err; } g_dc_di_assignment[1] = params->mem_dc_sync.di; ipu_dc_init(1, params->mem_dc_sync.di, params->mem_dc_sync.interlaced); ipu_di_use_count[params->mem_dc_sync.di]++; ipu_dc_use_count++; ipu_dmfc_use_count++; break; case MEM_BG_SYNC: if (params->mem_dp_bg_sync.di > 1) { ret = -EINVAL; goto err; } //printf("in_pixel_fmt: 0x%x, out_pixel_fmt: 0x%x\n", params->mem_dp_bg_sync.in_pixel_fmt, params->mem_dp_bg_sync.out_pixel_fmt); g_dc_di_assignment[5] = params->mem_dp_bg_sync.di; ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt, params->mem_dp_bg_sync.out_pixel_fmt); ipu_dc_init(5, params->mem_dp_bg_sync.di, params->mem_dp_bg_sync.interlaced); ipu_di_use_count[params->mem_dp_bg_sync.di]++; ipu_dc_use_count++; ipu_dp_use_count++; ipu_dmfc_use_count++; break; case MEM_FG_SYNC: ipu_dp_init(channel, params->mem_dp_fg_sync.in_pixel_fmt, params->mem_dp_fg_sync.out_pixel_fmt); ipu_dc_use_count++; ipu_dp_use_count++; ipu_dmfc_use_count++; break; default: printf("Missing channel initialization\n"); break; } if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) { printf("Warning--2: channel already initialized %d\n", IPU_CHAN_ID(channel)); }else{ /* Enable IPU sub module */ g_channel_init_mask |= 1L << IPU_CHAN_ID(channel); if (ipu_dc_use_count == 1) ipu_conf |= IPU_CONF_DC_EN; if (ipu_dp_use_count == 1) ipu_conf |= IPU_CONF_DP_EN; if (ipu_dmfc_use_count == 1) ipu_conf |= IPU_CONF_DMFC_EN; if (ipu_di_use_count[0] == 1) { ipu_conf |= IPU_CONF_DI0_EN; } if (ipu_di_use_count[1] == 1) { ipu_conf |= IPU_CONF_DI1_EN; } if (ipu_ic_use_count > 0) ipu_conf |= IPU_CONF_IC_EN; __raw_writel(ipu_conf, IPU_CONF); } err: return ret; }
/* * This function is called to initialize a buffer for logical IPU channel. * * @param channel Input parameter for the logical channel ID. * * @param type Input parameter which buffer to initialize. * * @param pixel_fmt Input parameter for pixel format of buffer. * Pixel format is a FOURCC ASCII code. * * @param width Input parameter for width of buffer in pixels. * * @param height Input parameter for height of buffer in pixels. * * @param stride Input parameter for stride length of buffer * in pixels. * * @param phyaddr_0 Input parameter buffer 0 physical address. * * @param phyaddr_1 Input parameter buffer 1 physical address. * Setting this to a value other than NULL enables * double buffering mode. * * @param u private u offset for additional cropping, * zero if not used. * * @param v private v offset for additional cropping, * zero if not used. * * @return Returns 0 on success or negative error code on fail */ int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type, uint32_t pixel_fmt, uint16_t width, uint16_t height, uint32_t stride, dma_addr_t phyaddr_0, dma_addr_t phyaddr_1, uint32_t u, uint32_t v) { uint32_t reg; uint32_t dma_chan; uint32_t burst_size; static int once = 0; if(IPU_CHAN_ID(channel) == 19){ if (once == 0){ once++; }else{ printf("ipu_init_channel_buffer fake reinit\n"); return 0; } } //printf("ipu_init_channel_buffer: channel: %d, type: %d, pixel_fmt: 0x%x, width: %d, height: %d, stride: %d, phyaddr_0: 0x%x, phyaddr_1: 0x%x, u: 0x%x, v: 0x%x\r\n", // IPU_CHAN_ID(channel), type, pixel_fmt, width, height,stride, phyaddr_0, phyaddr_1, u,v); dma_chan = channel_2_dma(channel, type); if (!idma_is_valid(dma_chan)) return -EINVAL; if (stride < width * bytes_per_pixel(pixel_fmt)){ stride = width * bytes_per_pixel(pixel_fmt); // printf("stride is update with bpp: 0x%x\n", bytes_per_pixel(pixel_fmt)); } if (stride % 4) { printf( "Stride not 32-bit aligned, stride = %d\n", stride); return -EINVAL; } /* Build parameter memory data for DMA channel */ ipu_ch_param_init(dma_chan, pixel_fmt, width, height, stride, u, v, 0, phyaddr_0, phyaddr_1); if (ipu_is_dmfc_chan(dma_chan)) { burst_size = _ipu_ch_param_get_burst_size(dma_chan); //printf("burst_size: 0x%x\n", burst_size); ipu_dmfc_set_wait4eot(dma_chan, width); ipu_dmfc_set_burst_size(dma_chan, burst_size); } /* IC and ROT channels have restriction of 8 or 16 pix burst length */ if (_ipu_is_ic_chan(dma_chan)) { if ((width % 16) == 0) _ipu_ch_param_set_burst_size(dma_chan, 16); else _ipu_ch_param_set_burst_size(dma_chan, 8); } if (_ipu_is_ic_chan(dma_chan) ) { burst_size = _ipu_ch_param_get_burst_size(dma_chan); _ipu_ic_idma_init(dma_chan, width, height, burst_size); } else if (_ipu_is_smfc_chan(dma_chan)) { burst_size = _ipu_ch_param_get_burst_size(dma_chan); if ((pixel_fmt == IPU_PIX_FMT_GENERIC) && ((_ipu_ch_param_get_bpp(dma_chan) == 5) || (_ipu_ch_param_get_bpp(dma_chan) == 3))) burst_size = burst_size >> 4; else burst_size = burst_size >> 2; _ipu_smfc_set_burst_size(channel, burst_size-1); }