?? mx27_prpsw.c
字號:
cam->rot_vf_buf_size[i] = cam->win.w.width * cam->win.w.height * 2; cam->rot_vf_bufs_vaddr[i] = dma_alloc_coherent(0, cam->rot_vf_buf_size[i], &cam->rot_vf_bufs[i], GFP_DMA | GFP_KERNEL); if (!cam->rot_vf_bufs_vaddr[i]) { pr_debug("Failed to alloc memory for vf rotation.\n"); prp_rot_mem_free(cam); return -1; } g_vaddr_rotbuf[i] = ioremap_cached(cam->rot_vf_bufs[i], cam->rot_vf_buf_size[i]); if (!g_vaddr_rotbuf[i]) { pr_debug ("Failed to ioremap_cached() for rotation buffer.\n"); prp_rot_mem_free(cam); return -1; } } return 0;}/*! * @brief Free intermedaite memory for overlay rotation/mirroring. * @param cam Pointer to cam_data structure * @return Zero on success, others on failure */static void prp_rot_mem_free(cam_data * cam){ int i; for (i = 0; i < 2; i++) { if (cam->rot_vf_bufs_vaddr[i]) { dma_free_coherent(0, cam->rot_vf_buf_size[i], cam->rot_vf_bufs_vaddr[i], cam->rot_vf_bufs[i]); } cam->rot_vf_bufs[i] = 0; cam->rot_vf_bufs_vaddr[i] = 0; cam->rot_vf_buf_size[i] = 0; if (g_vaddr_rotbuf[i]) { iounmap(g_vaddr_rotbuf[i]); g_vaddr_rotbuf[i] = 0; } }}/*! * @brief Start overlay (view finder). * @param private Pointer to cam_data structure * @return Zero on success, others on failure */static int prp_vf_start(void *private){ cam_data *cam = (cam_data *) private; if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) { prp_vf_mem_free(cam); if (prp_vf_mem_alloc(cam)) { pr_info("Error to allocate vf buffer\n"); return -ENOMEM; } } if (cam->rotation != V4L2_MXC_ROTATE_NONE) { prp_rot_mem_free(cam); if (prp_rot_mem_alloc(cam)) { pr_info("Error to allocate rotation buffer\n"); prp_vf_mem_free(cam); return -ENOMEM; } } if (prp_v4l2_cfg(&g_prp_cfg, cam)) { prp_vf_mem_free(cam); prp_rot_mem_free(cam); return -1; } csi_enable_mclk(CSI_MCLK_VF, true, true); prphw_reset(); if (prphw_cfg(&g_prp_cfg)) { prp_vf_mem_free(cam); prp_rot_mem_free(cam); return -1; } g_vfbuf = g_rotbuf = 0; tasklet_init(&prp_vf_tasklet, rotation, (unsigned long)private); prphw_enable(cam->capture_on ? (PRP_CHANNEL_1 | PRP_CHANNEL_2) : PRP_CHANNEL_1); return 0;}/*! * @brief Stop overlay (view finder). * @param private Pointer to cam_data structure * @return Zero on success, others on failure */static int prp_vf_stop(void *private){ cam_data *cam = (cam_data *) private; prphw_disable(PRP_CHANNEL_1); csi_enable_mclk(CSI_MCLK_VF, false, false); tasklet_kill(&prp_vf_tasklet); if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) { struct fb_gwinfo gwinfo; /* Disable graphic window */ gwinfo.enabled = 0; mx2_gw_set(&gwinfo); prp_vf_mem_free(cam); } prp_rot_mem_free(cam); if (g_vaddr_fb) { iounmap(g_vaddr_fb); g_vaddr_fb = 0; } return 0;}/*! * @brief Setup overlay functions. * @param private Pointer to cam_data structure * @return Zero on success, others on failure */int prp_vf_select(void *private){ int ret = 0; cam_data *cam = (cam_data *) private; if (cam) { cam->vf_start_sdc = prp_vf_start; cam->vf_stop_sdc = prp_vf_stop; cam->overlay_active = false; } else ret = -EIO; return ret;}/*! * @brief Uninstall overlay functions. * @param private Pointer to cam_data structure * @return Zero on success, others on failure */int prp_vf_deselect(void *private){ int ret = 0; cam_data *cam = (cam_data *) private; ret = prp_vf_stop(private); if (cam) { cam->vf_start_sdc = NULL; cam->vf_stop_sdc = NULL; } return ret;}/*! * @brief Start still picture capture. * @param private Pointer to cam_data structure * @return Zero on success, others on failure */static int prp_still_start(void *private){ cam_data *cam = (cam_data *) private; g_still_on = 1; g_prp_cfg.ch2_ptr = (unsigned int)cam->still_buf; g_prp_cfg.ch2_ptr2 = 0; if (prp_v4l2_cfg(&g_prp_cfg, cam)) return -1; csi_enable_mclk(CSI_MCLK_RAW, true, true); prphw_reset(); if (prphw_cfg(&g_prp_cfg)) { g_still_on = 0; return -1; } prphw_enable(cam->overlay_on ? (PRP_CHANNEL_1 | PRP_CHANNEL_2) : PRP_CHANNEL_2); return 0;}/*! * @brief Stop still picture capture. * @param private Pointer to cam_data structure * @return Zero on success, others on failure */static int prp_still_stop(void *private){ prphw_disable(PRP_CHANNEL_2); csi_enable_mclk(CSI_MCLK_RAW, false, false); g_still_on = 0; return 0;}/*! * @brief Setup functions for still picture capture. * @param private Pointer to cam_data structure * @return Zero on success, others on failure */int prp_still_select(void *private){ cam_data *cam = (cam_data *) private; if (cam) { cam->csi_start = prp_still_start; cam->csi_stop = prp_still_stop; } return 0;}/*! * @brief Uninstall functions for still picture capture. * @param private Pointer to cam_data structure * @return Zero on success, others on failure */int prp_still_deselect(void *private){ cam_data *cam = (cam_data *) private; int err = 0; err = prp_still_stop(cam); if (cam) { cam->csi_start = NULL; cam->csi_stop = NULL; } return err;}/*! * @brief Perform software rotation or mirroring * @param private Argument passed to the tasklet */static void rotation(unsigned long private){ char *src, *dst; int width, height, s_stride, d_stride; int size; cam_data *cam = (cam_data *) private; src = g_vaddr_rotbuf[g_rotbuf]; size = cam->rot_vf_buf_size[g_rotbuf]; if ((cam->rotation == V4L2_MXC_ROTATE_90_RIGHT) || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_VFLIP) || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_HFLIP) || (cam->rotation == V4L2_MXC_ROTATE_90_LEFT)) { width = cam->win.w.height; height = cam->win.w.width; s_stride = cam->win.w.height << 1; } else { width = cam->win.w.width; height = cam->win.w.height; s_stride = cam->win.w.width << 1; } if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) { dst = g_vaddr_vfbuf[g_vfbuf]; d_stride = cam->win.w.width << 1; } else { /* The destination is the framebuffer */ struct fb_info *fb = cam->overlay_fb; if (!fb) return; dst = g_vaddr_fb; dst += cam->win.w.top * fb->var.xres_virtual * (fb->var.bits_per_pixel >> 3) + cam->win.w.left * (fb->var.bits_per_pixel >> 3); d_stride = fb->var.xres_virtual << 1; } /* * Invalidate the data in cache before performing the SW rotaion * or mirroring in case the image size is less than QVGA. For image * larger than QVGA it is not invalidated becase the invalidation * will consume much time while we don't see any artifacts on the * output if we don't perform invalidation for them. * Similarly we don't flush the data after SW rotation/mirroring. */ if (size < 320 * 240 * 2) consistent_sync(src, size, DMA_FROM_DEVICE); switch (cam->rotation) { case V4L2_MXC_ROTATE_VERT_FLIP: opl_vmirror_u16(src, s_stride, width, height, dst, d_stride); break; case V4L2_MXC_ROTATE_HORIZ_FLIP: opl_hmirror_u16(src, s_stride, width, height, dst, d_stride); break; case V4L2_MXC_ROTATE_180: opl_rotate180_u16(src, s_stride, width, height, dst, d_stride); break; case V4L2_MXC_ROTATE_90_RIGHT: opl_rotate90_u16(src, s_stride, width, height, dst, d_stride); break; case V4L2_MXC_ROTATE_90_RIGHT_VFLIP: opl_rotate90_vmirror_u16(src, s_stride, width, height, dst, d_stride); break; case V4L2_MXC_ROTATE_90_RIGHT_HFLIP: /* ROTATE_90_RIGHT_HFLIP = ROTATE_270_RIGHT_VFLIP */ opl_rotate270_vmirror_u16(src, s_stride, width, height, dst, d_stride); break; case V4L2_MXC_ROTATE_90_LEFT: opl_rotate270_u16(src, s_stride, width, height, dst, d_stride); break; default: return; } /* Config and display the graphic window */ if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) { struct fb_gwinfo gwinfo; gwinfo.enabled = 1; gwinfo.alpha_value = 255; gwinfo.ck_enabled = 0; gwinfo.xpos = cam->win.w.left; gwinfo.ypos = cam->win.w.top; gwinfo.xres = cam->win.w.width; gwinfo.yres = cam->win.w.height; gwinfo.xres_virtual = cam->win.w.width; gwinfo.vs_reversed = 0; gwinfo.base = (unsigned long)cam->vf_bufs[g_vfbuf]; mx2_gw_set(&gwinfo); g_vfbuf = g_vfbuf ? 0 : 1; }}/* * @brief Check if the resize ratio is supported based on the input and output * dimension * @param input input dimension * @param output output dimension * @return output dimension (should equal the parameter *output*) * -1 on failure */static int check_simple(scale_t * scale, int input, int output, int ch){ unsigned short int_out; /* PrP internel width or height */ unsigned short orig_out = output; if (prp_scale(scale, input, output, input, &orig_out, &int_out, ch)) return -1; /* resize failed */ else return int_out;}/*! * @brief Check if the resize ratio is supported by PrP channel 1 * @param cfg Pointer to emma_prp_cfg structure * @return Zero on success, others on failure */static int prp_resize_check_ch1(emma_prp_cfg * cfg){ int in_w, in_h, ch1_w, ch1_h, ch2_w, ch2_h, w, h; scale_t *pscale = &cfg->scale[0]; /* Ch1 width resize coeff */ if (cfg->ch1_pix == PRP_PIX1_UNUSED) return 0; in_w = cfg->in_width; in_h = cfg->in_height; ch1_w = cfg->ch1_width; ch1_h = cfg->ch1_height; ch2_w = cfg->ch2_width; ch2_h = cfg->ch2_height; /* * For channel 1, try parallel resize first. If the resize * ratio is not exactly supported, try cascade resize. If it * still fails, use parallel resize but with rounded value. */ w = check_simple(pscale, in_w, ch1_w, PRP_CHANNEL_1); h = check_simple(pscale + 1, in_h, ch1_h, PRP_CHANNEL_1); if ((in_w <= ch1_w * MAX_TBL) && (in_h <= MAX_TBL * ch1_h)) goto exit_parallel; if (cfg->ch2_pix != PRP_PIX2_UNUSED) { /* * Channel 2 is already used. The pscale is still pointing * to ch1 resize coeff for temporary use. */ if ((ch2_w * MAX_TBL <= ch1_w) && (ch2_h * MAX_TBL <= ch1_h)) { w = check_simple(pscale, ch2_w, ch1_w, PRP_CHANNEL_1); h = check_simple(pscale + 1, ch2_h, ch1_h, PRP_CHANNEL_1); goto exit_cascade; } } else { /* * Try cascade resize for width, width is multiple of 2. * Channel 2 is not used. So we have more values to pick * for channel 2 resize. */ if (in_w * MAX_TBL > ch1_w) { for (w = in_w / 2; w > ch1_w; w /= 2) { /* Ch1 width resize */ if (check_simple (pscale, w, ch1_w, PRP_CHANNEL_1) < 0) continue; /* Ch2 width resize */ ch2_w = check_simple(pscale + 2, in_w, w, PRP_CHANNEL_1); if (ch2_w < 0) { w = in_w / MAX_TBL; continue; } check_simple(pscale, ch2_w, ch1_w, PRP_CHANNEL_1); break; } } else { w = check_simple(pscale, in_w, ch1_w, PRP_CHANNEL_1); ch2_w = check_simple(pscale + 2, w, w, PRP_CHANNEL_1); } if (ch2_w >= ch1_w) { if (in_h * MAX_TBL > ch1_h) { /* try cascade resize for height */ for (h = in_h / 2; h > ch1_h; h /= 2) { /* Ch2 height resize */ if (check_simple (pscale + 1, h, ch1_h, PRP_CHANNEL_1) < 0) continue; /* Ch1 height resize */ ch2_h = check_simple(pscale + 3, in_h, h, PRP_CHANNEL_1); if (ch2_w < 0) { h = in_h / MAX_TBL; continue; } check_simple(pscale + 1, ch2_h, ch1_h, PRP_CHANNEL_1); break; } } else { h = check_simple(pscale + 1, in_h, ch1_h, PRP_CHANNEL_1); ch2_h = check_simple(pscale + 3, h, h, PRP_CHANNEL_1); } goto exit_cascade; } } pr_debug("Ch1 resize error.\n"); return -1; exit_parallel: cfg->ch1_scale.algo |= PRP_ALGO_BYPASS; pr_debug("ch1 parallel resize.\n"); pr_debug("original width = %d internel width = %d\n", ch1_w, w); pr_debug("original height = %d internel height = %d\n", ch1_h, h); return 0; exit_cascade: cfg->ch1_scale.algo &= ~PRP_ALGO_BYPASS; pr_debug("ch1 cascade resize.\n"); pr_debug("[width] in : ch2 : ch1=%d : %d : %d\n", in_w, ch2_w, ch1_w); pr_debug("[height] in : ch2 : ch1=%d : %d : %d\n", in_h, ch2_h, ch1_h); return 0;}/*! * @brief Check if the resize ratio is supported by PrP channel 2 * @param cfg Pointer to emma_prp_cfg structure * @return Zero on success, others on failure */static int prp_resize_check_ch2(emma_prp_cfg * cfg){ int w, h; scale_t *pscale = &cfg->scale[2]; /* Ch2 width resize coeff */ if (cfg->ch2_pix == PRP_PIX2_UNUSED) return 0; w = check_simple(pscale, cfg->in_width, cfg->ch2_width, PRP_CHANNEL_2); h = check_simple(pscale + 1, cfg->in_height, cfg->ch2_height, PRP_CHANNEL_2); if ((w != -1) && (h != -1)) { pr_debug("Ch2 resize.\n"); pr_debug("Original width = %d internel width = %d\n", cfg->ch2_width, w); pr_debug("Original height = %d internel height = %d\n", cfg->ch2_height, h); return 0; } else { pr_debug("Ch2 resize error.\n"); return -1; }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -