/** * ispresizer_config_datapath - Specifies which input to use in resizer module * @input: Indicates the module that gives the image to resizer. * * Sets up the default resizer configuration according to the arguments. * * Returns 0 if successful, or -1 if an unsupported input was requested. **/ int ispresizer_config_datapath(enum ispresizer_input input) { u32 cnt = 0; DPRINTK_ISPRESZ("ispresizer_config_datapath()+\n"); ispres_obj.resinput = input; switch (input) { case RSZ_OTFLY_YUV: cnt &= ~ISPRSZ_CNT_INPTYP; cnt &= ~ISPRSZ_CNT_INPSRC; ispresizer_set_inaddr(0); ispresizer_config_inlineoffset(0); break; case RSZ_MEM_YUV: cnt |= ISPRSZ_CNT_INPSRC; cnt &= ~ISPRSZ_CNT_INPTYP; break; case RSZ_MEM_COL8: cnt |= ISPRSZ_CNT_INPSRC; cnt |= ISPRSZ_CNT_INPTYP; break; default: DPRINTK_ISPRESZ( "ISP_ERR : Wrong Input\n"); return -1; } isp_reg_or(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, cnt); //ispresizer_config_ycpos(0); ispresizer_config_ycpos(1); ispresizer_config_filter_coef(&ispreszdefcoef); ispresizer_enable_cbilin(0); ispresizer_config_luma_enhance(&ispreszdefaultyenh); DPRINTK_ISPRESZ("ispresizer_config_datapath()-\n"); return 0; }
/** * ispresizer_config_datapath - Specifies which input to use in resizer module * @input: Indicates the module that gives the image to resizer. * * Sets up the default resizer configuration according to the arguments. * * Returns 0 if successful, or -EINVAL if an unsupported input was requested. **/ int ispresizer_config_datapath(enum ispresizer_input input) { u32 cnt = 0; DPRINTK_ISPRESZ("ispresizer_config_datapath()+\n"); ispres_obj.resinput = input; switch (input) { case RSZ_OTFLY_YUV: cnt &= ~ISPRSZ_CNT_INPTYP; cnt &= ~ISPRSZ_CNT_INPSRC; ispresizer_set_inaddr(0); ispresizer_config_inlineoffset(0); break; case RSZ_MEM_YUV: cnt |= ISPRSZ_CNT_INPSRC; cnt &= ~ISPRSZ_CNT_INPTYP; break; case RSZ_MEM_COL8: cnt |= ISPRSZ_CNT_INPSRC; cnt |= ISPRSZ_CNT_INPTYP; break; default: printk(KERN_ERR "ISP_ERR : Wrong Input\n"); return -EINVAL; } isp_reg_or(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, cnt); /* Use bilinear interpolation for upsampling per TRM */ if (ispres_obj.outputwidth > ispres_obj.inputwidth) ispresizer_enable_cbilin(1); else ispresizer_enable_cbilin(0); ispresizer_config_ycpos(0); ispresizer_config_filter_coef(&ispreszdefcoef); ispresizer_config_luma_enhance(&ispreszdefaultyenh); DPRINTK_ISPRESZ("ispresizer_config_datapath()-\n"); return 0; }
/** * ispresizer_config_size - Configures input and output image size. * @input_w: input width for the resizer in number of pixels per line. * @input_h: input height for the resizer in number of lines. * @output_w: output width from the resizer in number of pixels per line. * @output_h: output height for the resizer in number of lines. * * Configures the appropriate values stored in the isp_res structure in the * resizer registers. * * Returns 0 if successful, or -EINVAL if passed values haven't been verified * with ispresizer_try_size() previously. **/ int ispresizer_config_size(u32 input_w, u32 input_h, u32 output_w, u32 output_h) { int i, j; u32 res; DPRINTK_ISPRESZ("ispresizer_config_size()+, input_w = %d,input_h =" " %d, output_w = %d, output_h" " = %d,hresz = %d,vresz = %d," " hcrop = %d, vcrop = %d," " hstph = %d, vstph = %d\n", ispres_obj.inputwidth, ispres_obj.inputheight, ispres_obj.outputwidth, ispres_obj.outputheight, ispres_obj.h_resz, ispres_obj.v_resz, ispres_obj.ipwd_crop, ispres_obj.ipht_crop, ispres_obj.h_startphase, ispres_obj.v_startphase); if ((output_w != ispres_obj.outputwidth) || (output_h != ispres_obj.outputheight)) { printk(KERN_ERR "Output parameters passed do not match the" " values calculated by the" " trysize passed w %d, h %d" " \n", output_w , output_h); return -EINVAL; } /* Set Resizer input address and offset adderss */ ispresizer_config_inlineoffset(isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WADD_OFFSET)); res = isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK); isp_reg_writel(res | (ispres_obj.h_startphase << ISPRSZ_CNT_HSTPH_SHIFT) | (ispres_obj.v_startphase << ISPRSZ_CNT_VSTPH_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT); /* Set start address for cropping */ isp_reg_writel(ispres_obj.tmp_buf + isp_get_buf_offset(), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD); /* isp_reg_writel( ((ispres_obj.ipwd_crop & 15) << ISPRSZ_IN_START_HORZ_ST_SHIFT) | (0x00 << ISPRSZ_IN_START_VERT_ST_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START); */ isp_reg_writel((0x00 << ISPRSZ_IN_START_HORZ_ST_SHIFT) | (0x00 << ISPRSZ_IN_START_VERT_ST_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START); isp_reg_writel((ispres_obj.inputwidth << ISPRSZ_IN_SIZE_HORZ_SHIFT) | (ispres_obj.inputheight << ISPRSZ_IN_SIZE_VERT_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE); if (!ispres_obj.algo) { isp_reg_writel((output_w << ISPRSZ_OUT_SIZE_HORZ_SHIFT) | (output_h << ISPRSZ_OUT_SIZE_VERT_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE); } else { isp_reg_writel(((output_w - 4) << ISPRSZ_OUT_SIZE_HORZ_SHIFT) | (output_h << ISPRSZ_OUT_SIZE_VERT_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE); } res = isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) & ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK); isp_reg_writel(res | ((ispres_obj.h_resz - 1) << ISPRSZ_CNT_HRSZ_SHIFT) | ((ispres_obj.v_resz - 1) << ISPRSZ_CNT_VRSZ_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT); /* write filter coefficients */ /* why not call isp_write_filter_coefs() ? */ if (ispres_obj.h_resz <= MID_RESIZE_VALUE) { j = 0; for (i = 0; i < 16; i++) { isp_reg_writel( (ispres_obj.coeflist.h_filter_coef_4tap[j] << ISPRSZ_HFILT10_COEF0_SHIFT) | (ispres_obj.coeflist.h_filter_coef_4tap[j + 1] << ISPRSZ_HFILT10_COEF1_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT10 + (i * 0x04)); j += 2; } } else { j = 0; for (i = 0; i < 16; i++) { if ((i + 1) % 4 == 0) { isp_reg_writel((ispres_obj.coeflist. h_filter_coef_7tap[j] << ISPRSZ_HFILT10_COEF0_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT10 + (i * 0x04)); j += 1; } else { isp_reg_writel((ispres_obj.coeflist. h_filter_coef_7tap[j] << ISPRSZ_HFILT10_COEF0_SHIFT) | (ispres_obj.coeflist. h_filter_coef_7tap[j+1] << ISPRSZ_HFILT10_COEF1_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT10 + (i * 0x04)); j += 2; } } } if (ispres_obj.v_resz <= MID_RESIZE_VALUE) { j = 0; for (i = 0; i < 16; i++) { isp_reg_writel((ispres_obj.coeflist. v_filter_coef_4tap[j] << ISPRSZ_VFILT10_COEF0_SHIFT) | (ispres_obj.coeflist. v_filter_coef_4tap[j + 1] << ISPRSZ_VFILT10_COEF1_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT10 + (i * 0x04)); j += 2; } } else { j = 0; for (i = 0; i < 16; i++) { if ((i + 1) % 4 == 0) { isp_reg_writel((ispres_obj.coeflist. v_filter_coef_7tap[j] << ISPRSZ_VFILT10_COEF0_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT10 + (i * 0x04)); j += 1; } else { isp_reg_writel((ispres_obj.coeflist. v_filter_coef_7tap[j] << ISPRSZ_VFILT10_COEF0_SHIFT) | (ispres_obj.coeflist. v_filter_coef_7tap[j+1] << ISPRSZ_VFILT10_COEF1_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT10 + (i * 0x04)); j += 2; } } } ispresizer_config_outlineoffset(output_w*2); DPRINTK_ISPRESZ("ispresizer_config_size()-\n"); return 0; }
int isp_resize_mem_data(struct isp_mem_resize_data *data) { int i; int ret = -1; struct isp_mem_resize_data *presizer_user = \ (struct isp_mem_resize_data *)data; u32 input_buffer_size, output_buffer_size; u32 input_nr_pages, output_nr_pages; struct page **input_pages = NULL; struct page **output_pages = NULL; unsigned long isp_addr_in = 0; unsigned long isp_addr_out = 0; struct isp_mem_resize_data resizer_param; unsigned long timeout; if (presizer_user == NULL) { printk(KERN_ERR "ISP_RESZ_ERR : Invalid user data\n"); return -EINVAL; } memcpy(&resizer_param, presizer_user, \ sizeof(struct isp_mem_resize_data)); DPRINTK_ISPPROC("\nRSZ input(%d-%d) - output(%d-%d)\n", resizer_param.input_width, resizer_param.input_height, resizer_param.output_width, resizer_param.output_height); DPRINTK_ISPPROC("RSZ start(%d-%d) - end(%d-%d)\n", resizer_param.left, resizer_param.top, resizer_param.crop_width, resizer_param.crop_height); if (presizer_user->datain == 0 || presizer_user->dataout == 0) return -EINVAL; ispresizer_enable(0); timeout = jiffies + msecs_to_jiffies(200); while (ispresizer_busy()) { if (time_after(jiffies, timeout)) return -EINVAL; msleep(1); } ispresizer_save_context(); ispresizer_free(); ispresizer_request(); /* set data path before configuring modules. */ ispresizer_config_datapath(RSZ_MEM_YUV, 0); input_buffer_size = ALIGN_TO(presizer_user->input_width* \ presizer_user->input_height*2 , 0x100); input_pages = map_user_memory_to_kernel(presizer_user->datain, input_buffer_size, &input_nr_pages); if (input_pages == NULL) { ret = -EINVAL; printk(KERN_ERR "ISP_RESZ_ERR: memory allocation failed\n"); goto exit_cleanup; } output_buffer_size = ALIGN_TO(presizer_user->output_width* \ presizer_user->output_height*2, 0x1000); output_pages = map_user_memory_to_kernel(presizer_user->dataout, output_buffer_size, &output_nr_pages); if (output_pages == NULL) { ret = -EINVAL; printk(KERN_ERR "ISP_RESZ_ERR: memory allocation failed\n"); goto exit_cleanup; } for (i = 0; i < output_nr_pages; ++i) flush_dcache_page(output_pages[i]); isp_addr_in = ispmmu_vmap_pages(input_pages, input_nr_pages); if (IS_ERR((void *)isp_addr_in)) { isp_addr_in = 0; ret = -EINVAL; printk(KERN_ERR "ISP_RESZ_ERR: isp mmu map failed\n"); goto exit_cleanup; } isp_addr_out = ispmmu_vmap_pages(output_pages, output_nr_pages); if (IS_ERR((void *)isp_addr_out)) { isp_addr_out = 0; ret = -EINVAL; printk(KERN_ERR "ISP_RESZ_ERR: isp mmu map failed\n"); goto exit_cleanup; } if ((resizer_param.left == 0) && (resizer_param.top == 0)) { ret = ispresizer_try_size(&resizer_param.input_width, &resizer_param.input_height, &resizer_param.output_width, &resizer_param.output_height); ret = ispresizer_config_size(resizer_param.input_width, resizer_param.input_height, resizer_param.output_width, resizer_param.output_height); ispresizer_set_inaddr(isp_addr_in); } else { ispresizer_trycrop(resizer_param.left, resizer_param.top, resizer_param.crop_width, resizer_param.crop_height, resizer_param.output_width, resizer_param.output_height); ispresizer_applycrop(); /*pixel alignment in 32bit space, vertical must be 0 per TRM */ isp_reg_writel(((resizer_param.left%16) << ISPRSZ_IN_START_HORZ_ST_SHIFT) | (0 << ISPRSZ_IN_START_VERT_ST_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START); /* Align input address for cropping, per TRM */ ispresizer_set_inaddr(isp_addr_in + (resizer_param.top*resizer_param.input_width*2) + ((resizer_param.left/16)*32)); } ispresizer_set_inaddr(isp_addr_in); ispresizer_set_outaddr(isp_addr_out); ispresizer_config_ycpos(0); ispresizer_config_inlineoffset( ALIGN_TO(presizer_user->input_width*2, 32)); isp_set_callback(CBK_RESZ_DONE, rsz_isr, (void *) NULL, (void *)NULL); isp_reg_writel(0xFFFFFFFF, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_wfc.done = 0; /* start resizer engine. */ ispresizer_enable(1); ret = wait_for_completion_timeout(&isp_wfc, msecs_to_jiffies(1000)); if (!ret) ispresizer_enable(0); timeout = jiffies + msecs_to_jiffies(50); while (ispresizer_busy()) { msleep(5); if (time_after(jiffies, timeout)) { printk(KERN_ERR "ISP_RESZ_ERR: Resizer still busy"); break; } } isp_reg_writel(0xFFFFFFFF, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_unset_callback(CBK_RESZ_DONE); ret = 0; exit_cleanup: ispresizer_restore_context(); if (isp_addr_in != 0) ispmmu_vunmap(isp_addr_in); if (isp_addr_out != 0) ispmmu_vunmap(isp_addr_out); if (input_pages != NULL) { unmap_user_memory_from_kernel(input_pages, input_nr_pages); kfree(input_pages); } if (output_pages != NULL) { unmap_user_memory_from_kernel(output_pages, output_nr_pages); kfree(output_pages); } DPRINTK_ISPPROC("resizer exit.\n"); return ret; }
int isp_process_mem_data(struct isp_mem_data *data) { int i; int ret = -1; struct isp_mem_data *ppreview_user = \ (struct isp_mem_data *)data; struct isp_mem_data preview_param; u32 input_buffer_size, output_buffer_size; u32 input_nr_pages, output_nr_pages; struct page **input_pages = NULL; struct page **output_pages = NULL; unsigned long isp_addr_in = 0; unsigned long isp_addr_out = 0; unsigned long isp_addr_tmp = 0; unsigned long timeout; struct isp_mem_resize_data resizer_param; u16 cropadjust = 0; if (ppreview_user == NULL) { printk(KERN_ERR "ISP_PROC_ERR: Invalid user data!\n"); return -EINVAL; } memcpy(&preview_param, ppreview_user, \ sizeof(struct isp_mem_data)); DPRINTK_ISPPROC("input(%d-%d) - output(%d-%d)\n", preview_param.input_width, preview_param.input_height, preview_param.output_width, preview_param.output_height); DPRINTK_ISPPROC("start(%d-%d) - end(%d-%d)\n", preview_param.left, preview_param.top, preview_param.crop_width, preview_param.crop_height); if (ppreview_user->datain == 0 || ppreview_user->dataout == 0) return -EINVAL; isppreview_enable(0); ispresizer_enable(0); timeout = jiffies + msecs_to_jiffies(200); while (isppreview_busy() || ispresizer_busy()) { if (time_after(jiffies, timeout)) return -EINVAL; msleep(1); } isppreview_save_context(); ispresizer_save_context(); isppreview_free(); ispresizer_free(); isppreview_request(); ispresizer_request(); /* set data path before configuring modules. */ isppreview_update_datapath(PRV_RAW_MEM, PREVIEW_MEM); ispresizer_config_datapath(RSZ_MEM_YUV, 0); ret = isppreview_try_size(preview_param.input_width, preview_param.input_height, &preview_param.output_width, &preview_param.output_height); if (ret < 0) goto exit_cleanup; ret = isppreview_config_size(preview_param.input_width, preview_param.input_height, preview_param.output_width, preview_param.output_height); if (ret < 0) goto exit_cleanup; input_buffer_size = ALIGN_TO(ppreview_user->input_width* \ ppreview_user->input_height*2 , 0x100); input_pages = map_user_memory_to_kernel(preview_param.datain, input_buffer_size, &input_nr_pages); if (input_pages == NULL) { ret = -EINVAL; printk(KERN_ERR "ISP_PROC_ERR: memory allocation failed\n"); goto exit_cleanup; } output_buffer_size = ALIGN_TO(ppreview_user->output_width* \ ppreview_user->output_height*2, 0x1000); output_pages = map_user_memory_to_kernel(preview_param.dataout, output_buffer_size, &output_nr_pages); if (output_pages == NULL) { ret = -EINVAL; printk(KERN_ERR "ISP_PROC_ERR: memory allocation failed\n"); goto exit_cleanup; } for (i = 0; i < output_nr_pages; ++i) flush_dcache_page(output_pages[i]); isp_addr_in = ispmmu_vmap_pages(input_pages, input_nr_pages); if (IS_ERR((void *)isp_addr_in)) { isp_addr_in = 0; ret = -EINVAL; printk(KERN_ERR "ISP_PROC_ERR: isp mmu map failed\n"); goto exit_cleanup; } isp_addr_out = ispmmu_vmap_pages(output_pages, output_nr_pages); if (IS_ERR((void *)isp_addr_out)) { isp_addr_out = 0; ret = -EINVAL; printk(KERN_ERR "ISP_PROC_ERR: isp mmu map failed\n"); goto exit_cleanup; } /* This buffer must be allocated and mapped to the ISP MMU previously. */ isp_addr_tmp = isp_tmp_buf_addr(); if (isp_addr_tmp == 0) { printk(KERN_ERR "ISP_PROC_ERR: Invalid isp tmp buffer address!\n"); goto exit_cleanup; } isppreview_config_inlineoffset(ppreview_user->input_width * 2); isppreview_set_inaddr(isp_addr_in); isppreview_set_outaddr(isp_addr_tmp); resizer_param.input_width = preview_param.output_width; resizer_param.input_height = preview_param.output_height; resizer_param.output_width = ppreview_user->output_width; resizer_param.output_height = ppreview_user->output_height; if ((preview_param.left == 0) && (preview_param.top == 0)) { ret = ispresizer_try_size(&resizer_param.input_width, &resizer_param.input_height, &resizer_param.output_width, &resizer_param.output_height); if (ret < 0) goto exit_cleanup; ret = ispresizer_config_size(resizer_param.input_width, resizer_param.input_height, resizer_param.output_width, resizer_param.output_height); if (ret < 0) goto exit_cleanup; ispresizer_set_inaddr(isp_addr_tmp); } else { ispresizer_trycrop(preview_param.left, preview_param.top, preview_param.crop_width, preview_param.crop_height, resizer_param.output_width, resizer_param.output_height); ispresizer_applycrop(); /* account for pixel loss when using crop*/ if ((preview_param.input_height > preview_param.output_height) && (preview_param.top > 16)) cropadjust = 8; else cropadjust = 0; /* pixel alignment in 32bit space, vertical must be 0 per TRM */ isp_reg_writel(((preview_param.left%16) << ISPRSZ_IN_START_HORZ_ST_SHIFT) | (0 << ISPRSZ_IN_START_VERT_ST_SHIFT), OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START); /* Align input address for cropping, per TRM */ ispresizer_set_inaddr(isp_addr_tmp - (resizer_param.input_width*2*cropadjust) + (preview_param.top*resizer_param.input_width*2) + ((preview_param.left/16)*32)); } ispresizer_set_outaddr(isp_addr_out); ispresizer_config_inlineoffset( ALIGN_TO(resizer_param.input_width*2, 32)); if (isp_set_callback(CBK_PREV_DONE, prv_isr, (void *) NULL, (void *)NULL) != 0) { printk(KERN_ERR "ISP_PROC_ERR: Error setting PRV callback.\n"); goto exit_cleanup; } if (isp_set_callback(CBK_RESZ_DONE, rsz_isr, (void *) NULL, (void *)NULL) != 0) { printk(KERN_ERR "ISP_PROC_ERR: Error setting RSZ callback.\n"); goto exit_cleanup; } isp_reg_writel(0xFFFFFFFF, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_wfc.done = 0; /* start preview engine. */ isppreview_enable(1); ret = wait_for_completion_timeout(&isp_wfc, msecs_to_jiffies(1000)); if (!ret) { isppreview_enable(0); ispresizer_enable(0); } timeout = jiffies + msecs_to_jiffies(50); while (ispresizer_busy()) { msleep(5); if (time_after(jiffies, timeout)) { printk(KERN_ERR "ISP_RESZ_ERR: Resizer still busy"); break; } } isp_reg_writel(0xFFFFFFFF, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS); isp_unset_callback(CBK_PREV_DONE); isp_unset_callback(CBK_RESZ_DONE); exit_cleanup: isppreview_restore_context(); ispresizer_restore_context(); if (isp_addr_in != 0) ispmmu_vunmap(isp_addr_in); if (isp_addr_out != 0) ispmmu_vunmap(isp_addr_out); if (input_pages != NULL) { unmap_user_memory_from_kernel(input_pages, input_nr_pages); kfree(input_pages); } if (output_pages != NULL) { unmap_user_memory_from_kernel(output_pages, output_nr_pages); kfree(output_pages); } DPRINTK_ISPPROC("exit.\n"); return ret; }