diff options
Diffstat (limited to 'drivers/media/sprd_scale/scale_drv.c')
| -rwxr-xr-x | drivers/media/sprd_scale/scale_drv.c | 770 |
1 files changed, 770 insertions, 0 deletions
diff --git a/drivers/media/sprd_scale/scale_drv.c b/drivers/media/sprd_scale/scale_drv.c new file mode 100755 index 00000000..c1a4002a --- /dev/null +++ b/drivers/media/sprd_scale/scale_drv.c @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2012 Spreadtrum Communications Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/bitops.h> +#include <linux/semaphore.h> +#include <linux/delay.h> +#include <asm/io.h> +#ifndef CONFIG_64BIT +#include <soc/sprd/hardware.h> +#endif +#include "scale_drv.h" +#include "gen_scale_coef.h" +#include "dcam_drv.h" + +#define SCALE_LOWEST_ADDR 0x800 +#define SCALE_ADDR_INVALIDE(addr) ((addr) < SCALE_LOWEST_ADDR) +#define SCALE_YUV_ADDR_INVALIDE(y,u,v) \ + (SCALE_ADDR_INVALIDE(y) && \ + SCALE_ADDR_INVALIDE(u) && \ + SCALE_ADDR_INVALIDE(v)) +#define SC_COEFF_H_TAB_OFFSET 0x1400 +#define SC_COEFF_V_TAB_OFFSET 0x14F0 +#define SC_COEFF_V_CHROMA_TAB_OFFSET 0x18F0 +#define SC_COEFF_COEF_SIZE (1 << 10) +#define SC_COEFF_TMP_SIZE (21 << 10) +#define SC_H_COEF_SIZE (0xC0) +#define SC_V_COEF_SIZE (0x210) +#define SC_V_CHROM_COEF_SIZE (0x210) +#define SC_COEFF_H_NUM (SC_H_COEF_SIZE / 4) +#define SC_COEFF_V_NUM (SC_V_COEF_SIZE / 4) +#define SC_COEFF_V_CHROMA_NUM (SC_V_CHROM_COEF_SIZE / 4) +#define SCALE_PIXEL_ALIGNED 4 +#define SCALE_SLICE_HEIGHT_ALIGNED 4 + +int scale_k_module_en(struct device_node *dn) +{ + int ret = 0; + + ret = dcam_get_resizer(DCAM_WAIT_FOREVER); + if (ret) { + printk("scale_module_en, failed to get review path %d \n", ret); + goto get_resizer_fail; + } + + ret = dcam_module_en(dn); + if (ret) { + printk("scale_module_en, failed to enable scale module %d \n", ret); + goto dcam_eb_fail; + } + + return ret; + +dcam_eb_fail: + dcam_rel_resizer(); +get_resizer_fail: + return ret; +} + +int scale_k_module_dis(struct device_node *dn) +{ + int ret = 0; + + ret = dcam_module_dis(dn); + if (ret) { + printk("scale_module_dis, failed to disable scale module %d \n", ret); + } + + ret = dcam_rel_resizer(); + if (ret) { + printk("scale_module_dis, failed to free review path %d \n", ret); + } + + return ret; +} + +static int scale_k_check_deci_slice_mode(uint32_t deci_val, uint32_t slice_h) +{ + int rtn = 0; + + if (deci_val > 0) { + if ((slice_h >= deci_val) && (0 == (slice_h % deci_val))) { + rtn = 0; + } else { + rtn = -1; + } + } + return rtn; +} + +static int scale_k_set_sc_coeff(struct scale_path_info *path_info_ptr) +{ + uint32_t i = 0; + unsigned long h_coeff_addr = SCALE_BASE; + unsigned long v_coeff_addr = SCALE_BASE; + unsigned long v_chroma_coeff_addr = SCALE_BASE; + uint32_t *tmp_buf = NULL; + uint32_t *h_coeff = NULL; + uint32_t *v_coeff = NULL; + uint32_t *v_chroma_coeff = NULL; + uint32_t scale2yuv420 = 0; + uint8_t y_tap = 0; + uint8_t uv_tap = 0; + + if (!path_info_ptr) { + printk("scale_k_set_sc_coeff error: path_info_ptr null \n"); + return -1; + } + + tmp_buf = (uint32_t *)path_info_ptr->coeff_addr; + if (NULL == tmp_buf) { + printk("scale_k_set_sc_coeff error: coeff mem null \n"); + return -1;; + } + + h_coeff_addr += SC_COEFF_H_TAB_OFFSET; + v_coeff_addr += SC_COEFF_V_TAB_OFFSET; + v_chroma_coeff_addr += SC_COEFF_V_CHROMA_TAB_OFFSET; + + if (SCALE_YUV420 == path_info_ptr->output_format) + scale2yuv420 = 1; + + h_coeff = tmp_buf; + v_coeff = tmp_buf + (SC_COEFF_COEF_SIZE/4); + v_chroma_coeff = v_coeff + (SC_COEFF_COEF_SIZE/4); + + if (!(GenScaleCoeff((int16_t)path_info_ptr->sc_input_size.w, + (int16_t)path_info_ptr->sc_input_size.h, + (int16_t)path_info_ptr->output_size.w, + (int16_t)path_info_ptr->output_size.h, + h_coeff, + v_coeff, + v_chroma_coeff, + scale2yuv420, + &y_tap, + &uv_tap, + tmp_buf + (SC_COEFF_COEF_SIZE*3/4), + SC_COEFF_TMP_SIZE))) { + printk("scale_k_set_sc_coeff error: gen scale coeff \n"); + return -1; + } + + for (i = 0; i < SC_COEFF_H_NUM; i++) { + REG_WR(h_coeff_addr, *h_coeff); + h_coeff_addr += 4; + h_coeff++; + } + + for (i = 0; i < SC_COEFF_V_NUM; i++) { + REG_WR(v_coeff_addr, *v_coeff); + v_coeff_addr += 4; + v_coeff++; + } + + for (i = 0; i < SC_COEFF_V_CHROMA_NUM; i++) { + REG_WR(v_chroma_coeff_addr, *v_chroma_coeff); + v_chroma_coeff_addr += 4; + v_chroma_coeff++; + } + + REG_MWR(SCALE_CFG, (BIT_19 | BIT_18 | BIT_17 | BIT_16), ((y_tap & 0x0F) << 16)); + REG_MWR(SCALE_CFG, (BIT_15 | BIT_14 | BIT_13 | BIT_12 | BIT_11), ((uv_tap & 0x1F) << 11)); + + return 0; +} + +static int scale_k_calc_sc_size(struct scale_path_info *path_info_ptr) +{ + int rtn = 0; + uint32_t reg_val = 0; + uint32_t div_factor = 1; + uint32_t i = 0, pixel_aligned_num = 0; + + if (!path_info_ptr) { + printk("scale_k_calc_sc_size error: path_info_ptr null \n"); + return -1; + } + + if (path_info_ptr->input_rect.w > (path_info_ptr->output_size.w * SCALE_SC_COEFF_MAX * (1 << SCALE_DECI_FAC_MAX)) || + path_info_ptr->input_rect.h > (path_info_ptr->output_size.h * SCALE_SC_COEFF_MAX * (1 << SCALE_DECI_FAC_MAX)) || + path_info_ptr->input_rect.w * SCALE_SC_COEFF_MAX < path_info_ptr->output_size.w || + path_info_ptr->input_rect.h * SCALE_SC_COEFF_MAX < path_info_ptr->output_size.h) { + printk("scale_k_calc_sc_size error: input{%d %d}, output{%d %d}\n", + path_info_ptr->input_rect.w, path_info_ptr->input_rect.h, + path_info_ptr->output_size.w, path_info_ptr->output_size.h); + rtn = -1; + } else { + path_info_ptr->sc_input_size.w = path_info_ptr->input_rect.w; + path_info_ptr->sc_input_size.h = path_info_ptr->input_rect.h; + if (path_info_ptr->input_rect.w > path_info_ptr->output_size.w * SCALE_SC_COEFF_MAX || + path_info_ptr->input_rect.h > path_info_ptr->output_size.h * SCALE_SC_COEFF_MAX) { + for (i = 0; i < SCALE_DECI_FAC_MAX; i++) { + div_factor = (uint32_t)(SCALE_SC_COEFF_MAX * (1 << (1 + i))); + if (path_info_ptr->input_rect.w <= (path_info_ptr->output_size.w * div_factor) && + path_info_ptr->input_rect.h <= (path_info_ptr->output_size.h * div_factor)) { + break; + } + } + path_info_ptr->sc_deci_val = (1 << (1 + i)); + pixel_aligned_num = (path_info_ptr->sc_deci_val >= SCALE_PIXEL_ALIGNED) ? path_info_ptr->sc_deci_val : SCALE_PIXEL_ALIGNED; + path_info_ptr->sc_input_size.w = path_info_ptr->input_rect.w >> (1 + i); + path_info_ptr->sc_input_size.h = path_info_ptr->input_rect.h >> (1 + i); + if ((path_info_ptr->sc_input_size.w % pixel_aligned_num) || + (path_info_ptr->sc_input_size.h % pixel_aligned_num)) { + path_info_ptr->sc_input_size.w = path_info_ptr->sc_input_size.w / pixel_aligned_num * pixel_aligned_num; + path_info_ptr->sc_input_size.h = path_info_ptr->sc_input_size.h / pixel_aligned_num * pixel_aligned_num; + path_info_ptr->input_rect.w = path_info_ptr->sc_input_size.w << (1 + i); + path_info_ptr->input_rect.h = path_info_ptr->sc_input_size.h << (1 + i); + } + + REG_WR(SCALE_TRIM_START, 0); + reg_val = path_info_ptr->sc_input_size.w | (path_info_ptr->sc_input_size.h << 16); + REG_WR(SCALE_TRIM_SIZE, reg_val); + REG_WR(SCALE_SRC_SIZE, reg_val); + + REG_OWR(SCALE_REV_BURST_IN_CFG, SCALE_BURST_SUB_EB_BIT); + REG_MWR(SCALE_REV_BURST_IN_CFG, SCALE_BURST_SUB_SAMPLE_MASK, (i << 13)); + REG_MWR(SCALE_REV_BURST_IN_CFG, SCALE_BURST_SRC_WIDTH_MASK, path_info_ptr->input_size.w); + reg_val = path_info_ptr->input_rect.x | (path_info_ptr->input_rect.y << 16); + REG_WR(SCALE_REV_BURST_IN_TRIM_START, reg_val); + reg_val = path_info_ptr->input_rect.w | (path_info_ptr->input_rect.h << 16); + REG_WR(SCALE_REV_BURST_IN_TRIM_SIZE, reg_val); + } + + } + + return rtn; +} + +static int scale_k_cfg_scaler(struct scale_path_info *path_info_ptr) +{ + int rtn = 0; + + if (!path_info_ptr) { + printk("scale_k_cfg_scaler error: path_info_ptr null \n"); + return -1; + } + + rtn = scale_k_calc_sc_size(path_info_ptr); + if (rtn) { + printk("scale_k_cfg_scaler error: calc \n"); + return rtn; + } + + if (path_info_ptr->sc_input_size.w != path_info_ptr->output_size.w || + path_info_ptr->sc_input_size.h != path_info_ptr->output_size.h || + SCALE_YUV420 == path_info_ptr->input_format) { + REG_MWR(SCALE_CFG, SCALE_BYPASS_BIT, 0); + rtn = scale_k_set_sc_coeff(path_info_ptr); + if (rtn) { + printk("scale_k_cfg_scaler error: coeff \n"); + } + } else { + REG_OWR(SCALE_CFG, SCALE_BYPASS_BIT); + } + + return rtn; +} + +int scale_k_slice_cfg(struct scale_slice_param_t *cfg_ptr, struct scale_path_info *path_info_ptr) +{ + int rtn = 0; + uint32_t reg_val = 0; + + if (!cfg_ptr || !path_info_ptr) { + printk("scale_k_io_cfg error: cfg_ptr=%p path_info_ptr=%p", + cfg_ptr, path_info_ptr); + return -1; + } + + /*set slice scale height*/ + if (cfg_ptr->slice_height > SCALE_FRAME_HEIGHT_MAX + || (cfg_ptr->slice_height % SCALE_SLICE_HEIGHT_ALIGNED)) { + printk("scale_k_io_cfg error: slice_height:%d \n", + cfg_ptr->slice_height); + rtn = -1; + goto cfg_exit; + } else { + REG_MWR(SCALE_REV_SLICE_CFG, SCALE_INPUT_SLICE_HEIGHT_MASK, cfg_ptr->slice_height); + path_info_ptr->slice_height = cfg_ptr->slice_height; + } + + /*set input rect*/ + if (cfg_ptr->input_rect.x > SCALE_FRAME_WIDTH_MAX + || cfg_ptr->input_rect.y > SCALE_FRAME_HEIGHT_MAX + || cfg_ptr->input_rect.w > SCALE_FRAME_WIDTH_MAX + || cfg_ptr->input_rect.h > SCALE_FRAME_HEIGHT_MAX) { + printk("scale_k_io_cfg error: input_rect {%d %d %d %d} \n", + cfg_ptr->input_rect.x, cfg_ptr->input_rect.y, + cfg_ptr->input_rect.w, cfg_ptr->input_rect.h); + rtn = -1; + goto cfg_exit; + } else { + reg_val = cfg_ptr->input_rect.x | (cfg_ptr->input_rect.y << 16); + REG_WR(SCALE_REV_BURST_IN_TRIM_START, reg_val); + REG_WR(SCALE_TRIM_START, 0); + reg_val = cfg_ptr->input_rect.w | (cfg_ptr->input_rect.h << 16); + REG_WR(SCALE_REV_BURST_IN_TRIM_SIZE, reg_val); + REG_WR(SCALE_TRIM_SIZE, reg_val); + REG_WR(SCALE_SRC_SIZE, reg_val); + memcpy((void*)&path_info_ptr->input_rect, (void*)&cfg_ptr->input_rect, + sizeof(struct scale_rect_t )); + } + + /*set input address*/ + if (SCALE_YUV_ADDR_INVALIDE(cfg_ptr->input_addr.yaddr, + cfg_ptr->input_addr.uaddr, cfg_ptr->input_addr.vaddr)) { + printk("scale_k_io_cfg error: input_addr {%x %x %x} \n", + cfg_ptr->input_addr.yaddr, cfg_ptr->input_addr.uaddr, + cfg_ptr->input_addr.vaddr); + rtn = -1; + goto cfg_exit; + } else { + REG_WR(SCALE_FRM_IN_Y, cfg_ptr->input_addr.yaddr); + REG_WR(SCALE_FRM_IN_U, cfg_ptr->input_addr.uaddr); + REG_WR(SCALE_FRM_IN_V, cfg_ptr->input_addr.vaddr); + path_info_ptr->input_addr.yaddr = cfg_ptr->input_addr.yaddr; + path_info_ptr->input_addr.uaddr = cfg_ptr->input_addr.uaddr; + path_info_ptr->input_addr.vaddr = cfg_ptr->input_addr.vaddr; + } + + /*set output address*/ + if (SCALE_YUV_ADDR_INVALIDE(cfg_ptr->output_addr.yaddr, + cfg_ptr->output_addr.uaddr, cfg_ptr->output_addr.vaddr)) { + printk("scale_k_io_cfg error: output_addr {%x %x %x} \n", + cfg_ptr->output_addr.yaddr, cfg_ptr->output_addr.uaddr, + cfg_ptr->output_addr.vaddr); + rtn = -1; + goto cfg_exit; + } else { + REG_WR(SCALE_FRM_OUT_Y, cfg_ptr->output_addr.yaddr); + REG_WR(SCALE_FRM_OUT_U, cfg_ptr->output_addr.uaddr); + REG_WR(SCALE_FRM_OUT_V, cfg_ptr->output_addr.vaddr); + path_info_ptr->output_addr.yaddr = cfg_ptr->output_addr.yaddr; + path_info_ptr->output_addr.uaddr = cfg_ptr->output_addr.uaddr; + path_info_ptr->output_addr.vaddr = cfg_ptr->output_addr.vaddr; + } + +cfg_exit: + return rtn; +} + +int scale_k_frame_cfg(struct scale_frame_param_t *cfg_ptr, struct scale_path_info *path_info_ptr) +{ + int rtn = 0; + uint32_t reg_val = 0; + + if (!cfg_ptr || !path_info_ptr) { + printk("scale_k_io_cfg error: cfg_ptr=%p path_info_ptr=%p", + cfg_ptr, path_info_ptr); + return -1; + } + + SCALE_TRACE("scale_k_io_cfg : input_size {%d %d} \n", + cfg_ptr->input_size.w, cfg_ptr->input_size.h); + /*set input size*/ + if (cfg_ptr->input_size.w > SCALE_FRAME_WIDTH_MAX + || cfg_ptr->input_size.h > SCALE_FRAME_HEIGHT_MAX) { + printk("scale_k_io_cfg error: input_size {%d %d} \n", + cfg_ptr->input_size.w, cfg_ptr->input_size.h); + rtn = -1; + goto cfg_exit; + } else { + REG_MWR(SCALE_REV_BURST_IN_CFG, SCALE_BURST_SUB_EB_BIT, 0); + REG_MWR(SCALE_REV_BURST_IN_CFG, SCALE_BURST_SUB_SAMPLE_MASK, 0); + REG_MWR(SCALE_REV_BURST_IN_CFG, SCALE_BURST_SRC_WIDTH_MASK, cfg_ptr->input_size.w); + path_info_ptr->input_size.w = cfg_ptr->input_size.w; + path_info_ptr->input_size.h= cfg_ptr->input_size.h; + } + + SCALE_TRACE("scale_k_io_cfg : input_rect {%d %d %d %d} \n", + cfg_ptr->input_rect.x, cfg_ptr->input_rect.y, + cfg_ptr->input_rect.w, cfg_ptr->input_rect.h); + /*set input rect*/ + if (cfg_ptr->input_rect.x > SCALE_FRAME_WIDTH_MAX + || cfg_ptr->input_rect.x > SCALE_FRAME_HEIGHT_MAX + || cfg_ptr->input_rect.w > SCALE_FRAME_WIDTH_MAX + || cfg_ptr->input_rect.h > SCALE_FRAME_HEIGHT_MAX) { + printk("scale_k_io_cfg error: input_rect {%d %d %d %d} \n", + cfg_ptr->input_rect.x, cfg_ptr->input_rect.y, + cfg_ptr->input_rect.w, cfg_ptr->input_rect.h); + rtn = -1; + goto cfg_exit; + } else { + reg_val = cfg_ptr->input_rect.x | (cfg_ptr->input_rect.y << 16); + REG_WR(SCALE_REV_BURST_IN_TRIM_START, reg_val); + REG_WR(SCALE_TRIM_START, 0); + reg_val = cfg_ptr->input_rect.w | (cfg_ptr->input_rect.h << 16); + REG_WR(SCALE_REV_BURST_IN_TRIM_SIZE, reg_val); + REG_WR(SCALE_TRIM_SIZE, reg_val); + REG_WR(SCALE_SRC_SIZE, reg_val); + memcpy((void*)&path_info_ptr->input_rect, (void*)&cfg_ptr->input_rect, + sizeof(struct scale_rect_t )); + } + + SCALE_TRACE("scale_k_io_cfg : input_format:%d \n", + cfg_ptr->input_format); + /*set input foramt*/ + path_info_ptr->input_format = cfg_ptr->input_format; + if (SCALE_YUV422 == cfg_ptr->input_format + || SCALE_YUV420 == cfg_ptr->input_format || + SCALE_YUV420_3FRAME == cfg_ptr->input_format) { + REG_MWR(SCALE_REV_BURST_IN_CFG, SCALE_BURST_INPUT_MODE_MASK, (cfg_ptr->input_format << 16)); + } else { + printk("scale_k_io_cfg error: input_format:%d \n", + cfg_ptr->input_format); + rtn = -1; + goto cfg_exit; + } + + SCALE_TRACE("scale_k_io_cfg : input_addr {%x %x %x} \n", + cfg_ptr->input_addr.yaddr, cfg_ptr->input_addr.uaddr, + cfg_ptr->input_addr.vaddr); + /*set input address*/ + if (SCALE_YUV_ADDR_INVALIDE(cfg_ptr->input_addr.yaddr, + cfg_ptr->input_addr.uaddr, cfg_ptr->input_addr.vaddr)) { + printk("scale_k_io_cfg error: input_addr {%x %x %x} \n", + cfg_ptr->input_addr.yaddr, cfg_ptr->input_addr.uaddr, + cfg_ptr->input_addr.vaddr); + rtn = -1; + goto cfg_exit; + } else { + REG_WR(SCALE_FRM_IN_Y, cfg_ptr->input_addr.yaddr); + REG_WR(SCALE_FRM_IN_U, cfg_ptr->input_addr.uaddr); + REG_WR(SCALE_FRM_IN_V, cfg_ptr->input_addr.vaddr); + path_info_ptr->input_addr.yaddr = cfg_ptr->input_addr.yaddr; + path_info_ptr->input_addr.uaddr = cfg_ptr->input_addr.uaddr; + path_info_ptr->input_addr.vaddr = cfg_ptr->input_addr.vaddr; + } + + SCALE_TRACE("scale_k_io_cfg : input_endian {%d %d} \n", + cfg_ptr->input_endian.y_endian, cfg_ptr->input_endian.uv_endian); + /*set input endian*/ + if (cfg_ptr->input_endian.y_endian >= SCALE_ENDIAN_MAX + ||cfg_ptr->input_endian.uv_endian >= SCALE_ENDIAN_MAX) { + printk("scale_k_io_cfg error: input_endian {%d %d} \n", + cfg_ptr->input_endian.y_endian, cfg_ptr->input_endian.uv_endian); + rtn = -1; + goto cfg_exit; + } else { + cfg_ptr->input_endian.uv_endian = cfg_ptr->input_endian.y_endian; + dcam_glb_reg_owr(SCALE_ENDIAN_SEL,(SCALE_AXI_RD_ENDIAN_BIT | SCALE_AXI_WR_ENDIAN_BIT), DCAM_ENDIAN_REG); + dcam_glb_reg_mwr(SCALE_ENDIAN_SEL, SCALE_INPUT_Y_ENDIAN_MASK, cfg_ptr->input_endian.y_endian, DCAM_ENDIAN_REG); + dcam_glb_reg_mwr(SCALE_ENDIAN_SEL, SCALE_INPUT_UV_ENDIAN_MASK, (cfg_ptr->input_endian.uv_endian << 2), DCAM_ENDIAN_REG); + SCALE_TRACE("scale_k_io_cfg: output_endian {%d %d} 0x%x \n", + cfg_ptr->input_endian.y_endian, cfg_ptr->input_endian.uv_endian, REG_RD(SCALE_ENDIAN_SEL)); + } + + SCALE_TRACE("scale_k_io_cfg: output_size {%d %d} \n", + cfg_ptr->output_size.w, cfg_ptr->output_size.h); + + /*set output size*/ + if (cfg_ptr->output_size.w > SCALE_FRAME_WIDTH_MAX || + cfg_ptr->output_size.h > SCALE_FRAME_HEIGHT_MAX) { + printk("scale_k_io_cfg error: output_size {%d %d} \n", + cfg_ptr->output_size.w, cfg_ptr->output_size.h); + rtn = -1; + goto cfg_exit; + } else { + reg_val = cfg_ptr->output_size.w | (cfg_ptr->output_size.h << 16); + REG_WR(SCALE_DST_SIZE, reg_val); + path_info_ptr->output_size.w = cfg_ptr->output_size.w; + path_info_ptr->output_size.h = cfg_ptr->output_size.h; + } + + SCALE_TRACE("scale_k_io_cfg: output_format:%d \n", + cfg_ptr->output_format); + + /*set output format*/ + path_info_ptr->output_format = cfg_ptr->output_format; + if (SCALE_YUV422 == cfg_ptr->output_format) { + REG_MWR(SCALE_CFG, SCALE_OUTPUT_MODE_MASK, (0 << 6)); + } else if (SCALE_YUV420 == cfg_ptr->output_format) { + REG_MWR(SCALE_CFG, SCALE_OUTPUT_MODE_MASK, (1 << 6)); + } else if (SCALE_YUV420_3FRAME == cfg_ptr->output_format) { + REG_MWR(SCALE_CFG, SCALE_OUTPUT_MODE_MASK, (3 << 6)); + } else { + printk("scale_k_io_cfg error: output_format:%d \n", + cfg_ptr->output_format); + rtn = -1; + goto cfg_exit; + } + + SCALE_TRACE("scale_k_io_cfg : output_addr {%x %x %x} \n", + cfg_ptr->output_addr.yaddr, cfg_ptr->output_addr.uaddr, + cfg_ptr->output_addr.vaddr); + + /*set output address*/ + if (SCALE_YUV_ADDR_INVALIDE(cfg_ptr->output_addr.yaddr, + cfg_ptr->output_addr.uaddr, cfg_ptr->output_addr.vaddr)) { + printk("scale_k_io_cfg error: output_addr {%x %x %x} \n", + cfg_ptr->output_addr.yaddr, cfg_ptr->output_addr.uaddr, + cfg_ptr->output_addr.vaddr); + rtn = -1; + goto cfg_exit; + } else { + REG_WR(SCALE_FRM_OUT_Y, cfg_ptr->output_addr.yaddr); + REG_WR(SCALE_FRM_OUT_U, cfg_ptr->output_addr.uaddr); + REG_WR(SCALE_FRM_OUT_V, cfg_ptr->output_addr.vaddr); + path_info_ptr->output_addr.yaddr = cfg_ptr->output_addr.yaddr; + path_info_ptr->output_addr.uaddr = cfg_ptr->output_addr.uaddr; + path_info_ptr->output_addr.vaddr = cfg_ptr->output_addr.vaddr; + } + + SCALE_TRACE("scale_k_io_cfg: output_endian {%d %d} \n", + cfg_ptr->output_endian.y_endian, cfg_ptr->output_endian.uv_endian); + + /*set output endian*/ + if (cfg_ptr->output_endian.y_endian >= SCALE_ENDIAN_MAX || + cfg_ptr->output_endian.uv_endian >= SCALE_ENDIAN_MAX) { + printk("scale_k_io_cfg error: output_endian {%d %d} \n", + cfg_ptr->output_endian.y_endian, cfg_ptr->output_endian.uv_endian); + rtn = -1; + goto cfg_exit; + } else { + cfg_ptr->output_endian.uv_endian = cfg_ptr->output_endian.y_endian; + dcam_glb_reg_owr(SCALE_ENDIAN_SEL,(SCALE_AXI_RD_ENDIAN_BIT|SCALE_AXI_WR_ENDIAN_BIT), DCAM_ENDIAN_REG); + dcam_glb_reg_mwr(SCALE_ENDIAN_SEL, SCALE_OUTPUT_Y_ENDIAN_MASK, (cfg_ptr->output_endian.y_endian << 10), DCAM_ENDIAN_REG); + dcam_glb_reg_mwr(SCALE_ENDIAN_SEL, SCALE_OUTPUT_UV_ENDIAN_MASK, (cfg_ptr->output_endian.uv_endian<< 12), DCAM_ENDIAN_REG); + SCALE_TRACE("scale_k_io_cfg: output_endian {%d %d} 0x%x \n", + cfg_ptr->output_endian.y_endian, cfg_ptr->output_endian.uv_endian, REG_RD(SCALE_ENDIAN_SEL)); + } + + SCALE_TRACE("scale_k_io_cfg: scale_mode:%d \n", + cfg_ptr->scale_mode); + + /*set scale mode*/ + if (cfg_ptr->scale_mode >= SCALE_MODE_MAX) { + printk("scale_k_io_cfg error: scale_mode:%d \n", + cfg_ptr->scale_mode); + rtn = -1; + goto cfg_exit; + } else { + if (SCALE_MODE_NORMAL == cfg_ptr->scale_mode) { + REG_MWR(SCALE_CFG, SCALE_MODE_MASK, SCALE_MODE_NORMAL_TYPE); + } else if(SCALE_MODE_SLICE == cfg_ptr->scale_mode) { + REG_MWR(SCALE_CFG, SCALE_MODE_MASK, SCALE_MODE_SLICE_TYPE); + REG_MWR(SCALE_REV_SLICE_CFG, SCALE_SLICE_TYPE_BIT, 0); + }else{ + REG_MWR(SCALE_CFG, SCALE_MODE_MASK, SCALE_MODE_SLICE_TYPE); + REG_OWR(SCALE_REV_SLICE_CFG, SCALE_SLICE_TYPE_BIT); + } + path_info_ptr->scale_mode = cfg_ptr->scale_mode; + } + + /*set slice scale height*/ + if (SCALE_MODE_SLICE == cfg_ptr->scale_mode + || SCALE_MODE_SLICE_READDR ==cfg_ptr->scale_mode) { + if (cfg_ptr->slice_height > SCALE_FRAME_HEIGHT_MAX + || (cfg_ptr->slice_height % SCALE_SLICE_HEIGHT_ALIGNED)) { + printk("scale_k_io_cfg error: slice_height:%d \n", + cfg_ptr->slice_height); + rtn = -1; + goto cfg_exit; + } else { + REG_MWR(SCALE_REV_SLICE_CFG, SCALE_INPUT_SLICE_HEIGHT_MASK, cfg_ptr->slice_height); + path_info_ptr->slice_height = cfg_ptr->slice_height; + } + } + +cfg_exit: + return rtn; +} + +int scale_k_start(struct scale_frame_param_t *cfg_ptr, struct scale_path_info *path_info_ptr) +{ + int rtn = 0; + + if (!path_info_ptr) { + printk("scale_k_start error: path_info_ptr null \n"); + return -1; + } + + dcam_resize_start(); + + rtn = scale_k_frame_cfg(cfg_ptr, path_info_ptr); + if (rtn) { + printk("scale_k_start error: frame cfg \n"); + goto start_exit; + } + + if (SCALE_MODE_NORMAL == path_info_ptr->scale_mode) { + if (path_info_ptr->output_size.w > SCALE_FRAME_WIDTH_MAX) { + rtn = -1; + printk("scale_k_start error: frame output_size_w=%d \n", + path_info_ptr->output_size.w); + goto start_exit; + } + } else { + if (path_info_ptr->output_size.w > SCALE_LINE_BUF_LENGTH) { + rtn = -1; + printk("scale_k_start error: frame output_size_w=%d \n", + path_info_ptr->output_size.w); + goto start_exit; + } + } + + path_info_ptr->slice_in_height = 0; + path_info_ptr->slice_out_height = 0; + path_info_ptr->is_last_slice = 0; + path_info_ptr->sc_deci_val = 0; + + REG_MWR(SCALE_CFG, (SCALE_DEC_X_EB_BIT|SCALE_DEC_Y_EB_BIT), 0); + + rtn = scale_k_cfg_scaler(path_info_ptr); + if (rtn) { + printk("scale_k_start error: cfg \n"); + goto start_exit; + } + + if (SCALE_MODE_NORMAL != path_info_ptr->scale_mode) { + path_info_ptr->slice_in_height += path_info_ptr->slice_height; + rtn = scale_k_check_deci_slice_mode(path_info_ptr->sc_deci_val, path_info_ptr->slice_height); + if (rtn) goto start_exit; + } + dcam_glb_reg_mwr(SCALE_BASE, SCALE_PATH_MASK, SCALE_PATH_SELECT, DCAM_CFG_REG); + dcam_glb_reg_owr(SCALE_BASE, SCALE_PATH_EB_BIT, DCAM_CFG_REG); + + dcam_glb_reg_owr(SCALE_CTRL, (SCALE_FRC_COPY_BIT|SCALE_COEFF_FRC_COPY_BIT), DCAM_CONTROL_REG); + REG_OWR(SCALE_REV_BURST_IN_CFG, SCALE_START_BIT); + REG_WR(SCALE_BURST_GAP, 0x100000); + printk("scale_k_start\n"); + return rtn; + +start_exit: + dcam_resize_end(); + SCALE_TRACE("scale_k_start error: ret=%d \n", rtn); + return rtn; +} + +int scale_k_continue(struct scale_slice_param_t *cfg_ptr, struct scale_path_info *path_info_ptr) +{ + int rtn = 0; + uint32_t slice_h = 0; + + if (!path_info_ptr) { + printk("scale_k_continue error: path_info_ptr null \n"); + return -1; + } + + rtn = scale_k_slice_cfg(cfg_ptr, path_info_ptr); + if (rtn) { + printk("rot_k_ioctl error: slice cfg \n"); + return -1; + } + + + SCALE_TRACE("scale_k_continue: { %d, %d, %d} \n", + path_info_ptr->slice_height, path_info_ptr->slice_in_height, path_info_ptr->scale_mode); + + if (SCALE_MODE_NORMAL != path_info_ptr->scale_mode) { + if (path_info_ptr->slice_in_height + path_info_ptr->slice_height >= path_info_ptr->input_rect.h) { + slice_h = path_info_ptr->input_rect.h - path_info_ptr->slice_in_height; + if (scale_k_check_deci_slice_mode(path_info_ptr->sc_deci_val, slice_h)) { + printk("scale_k_continue error: check deci \n"); + return -1; + } + path_info_ptr->is_last_slice = 1; + REG_MWR(SCALE_REV_SLICE_CFG, SCALE_INPUT_SLICE_HEIGHT_MASK, slice_h); + REG_OWR(SCALE_REV_SLICE_CFG, SCALE_IS_LAST_SLICE_BIT); + } else { + path_info_ptr->is_last_slice = 0; + REG_MWR(SCALE_REV_SLICE_CFG, SCALE_IS_LAST_SLICE_BIT, 0); + } + path_info_ptr->slice_in_height += path_info_ptr->slice_height; + } + + dcam_glb_reg_owr(SCALE_CTRL, SCALE_START_BIT, DCAM_CONTROL_REG); + + return rtn; +} + +int scale_k_stop(void) +{ + int rtn = 0; + + dcam_glb_reg_mwr(SCALE_BASE, SCALE_PATH_EB_BIT, 0, DCAM_CFG_REG); + + return rtn; +} + +int scale_k_isr(struct dcam_frame* dcam_frm, void* u_data) +{ + unsigned long flag; + scale_isr_func user_isr_func; + struct scale_drv_private *private = (struct scale_drv_private *)u_data; + struct scale_path_info *path_info_ptr; + struct scale_frame_info_t *frm_info_ptr; + + if (!private) { + printk("scale_k_isr error: private null \n"); + goto isr_exit; + } + + user_isr_func = private->user_isr_func; + if (!user_isr_func) { + printk("scale_k_isr error: user_isr_func null \n"); + goto isr_exit; + } + path_info_ptr = &private->path_info; + frm_info_ptr = &private->frm_info; + + spin_lock_irqsave(&private->scale_drv_lock, flag); + + memset(frm_info_ptr, 0, sizeof(struct scale_frame_info_t)); + frm_info_ptr->yaddr = path_info_ptr->output_addr.yaddr; + frm_info_ptr->uaddr = path_info_ptr->output_addr.uaddr; + frm_info_ptr->vaddr = path_info_ptr->output_addr.vaddr; + frm_info_ptr->width = path_info_ptr->output_size.w; + if (SCALE_MODE_NORMAL != path_info_ptr->scale_mode) { + frm_info_ptr->height_uv = REG_RD(SCALE_REV_SLICE_O_VCNT); + frm_info_ptr->height_uv = (frm_info_ptr->height_uv >> 16) & SCALE_OUTPUT_SLICE_HEIGHT_MASK; + frm_info_ptr->height = REG_RD(SCALE_REV_SLICE_O_VCNT); + frm_info_ptr->height = frm_info_ptr->height & SCALE_OUTPUT_SLICE_HEIGHT_MASK; + path_info_ptr->slice_out_height += frm_info_ptr->height; + } else { + frm_info_ptr->height = path_info_ptr->output_size.h; + } + + if (path_info_ptr->is_wait_stop) { + up(&path_info_ptr->done_sem); + path_info_ptr->is_wait_stop = 0; + } + if (SCALE_MODE_NORMAL == path_info_ptr->scale_mode || + (SCALE_MODE_NORMAL != path_info_ptr->scale_mode && path_info_ptr->output_size.h == path_info_ptr->slice_out_height)) { + printk("begin to dcam_resize_end\n"); + dcam_resize_end(); + } + user_isr_func(private->scale_fd); + spin_unlock_irqrestore(&private->scale_drv_lock, flag); + +isr_exit: + return 0; +} + +int scale_k_isr_reg(scale_isr_func user_func, struct scale_drv_private *drv_private) +{ + int rtn = 0; + unsigned long flag; + + if (user_func) { + if (!drv_private) { + rtn = -1; + printk("scale_reg_isr Failed \n"); + goto reg_exit; + } + + spin_lock_irqsave(&drv_private->scale_drv_lock, flag); + drv_private->user_isr_func = user_func; + spin_unlock_irqrestore(&drv_private->scale_drv_lock, flag); + + dcam_reg_isr(DCAM_PATH2_DONE, scale_k_isr, (void *)drv_private); + } else { + dcam_reg_isr(DCAM_PATH2_DONE, NULL, NULL); + } + +reg_exit: + return rtn; +} |
