?? mx27_pp.c
字號:
/* * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. *//* * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: * * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html *//*! * @file mx27_pp.c * * @brief MX27 V4L2 Video Output Driver * * Video4Linux2 Output Device using MX27 eMMA Post-processing functionality. * * @ingroup MXC_V4L2_OUTPUT */#include <linux/kernel.h>#include <linux/string.h>#include <linux/module.h>#include <linux/fb.h>#include <linux/clk.h>#include <linux/interrupt.h>#include <asm/io.h>#include "mx27_pp.h"#include "mxc_v4l2_output.h"#define SCALE_RETRY 32 /* to be more relax, less precise */#define PP_SKIP 1#define PP_TBL_MAX 40static unsigned short scale_tbl[PP_TBL_MAX];static int g_hlen, g_vlen;static emma_pp_cfg g_pp_cfg;static int g_disp_num = 0;static char pp_dev[] = "emma_pp";/*! * @brief PP resizing routines */static int gcd(int x, int y);static int ratio(int x, int y, int *den);static int scale_0d(int k, int coeff, int base, int nxt);static int scale_1d(int inv, int outv, int k);static int scale_1d_smart(int *inv, int *outv, int index);static int scale_2d(emma_pp_scale * sz);static irqreturn_t pp_isr(int irq, void *dev_id);static int set_output_addr(emma_pp_cfg * cfg, vout_data * vout);static int pphw_reset(void);static int pphw_enable(int flag);static int pphw_ptr(emma_pp_cfg * cfg);static int pphw_outptr(emma_pp_cfg * cfg);static int pphw_cfg(emma_pp_cfg * cfg);static int pphw_isr(void);static void pphw_init(void);static void pphw_exit(void);#define PP_DUMP(reg) pr_debug("%s\t = 0x%08X\n", #reg, __raw_readl(reg))void pp_dump(void){ PP_DUMP(PP_CNTL); PP_DUMP(PP_INTRCNTL); PP_DUMP(PP_INTRSTATUS); PP_DUMP(PP_SOURCE_Y_PTR); PP_DUMP(PP_SOURCE_CB_PTR); PP_DUMP(PP_SOURCE_CR_PTR); PP_DUMP(PP_DEST_RGB_PTR); PP_DUMP(PP_QUANTIZER_PTR); PP_DUMP(PP_PROCESS_FRAME_PARA); PP_DUMP(PP_SOURCE_FRAME_WIDTH); PP_DUMP(PP_DEST_DISPLAY_WIDTH); PP_DUMP(PP_DEST_IMAGE_SIZE); PP_DUMP(PP_DEST_FRAME_FMT_CNTL); PP_DUMP(PP_RESIZE_INDEX); PP_DUMP(PP_CSC_COEF_0123); PP_DUMP(PP_CSC_COEF_4);}static const unsigned char pp_coeftab[] = { 2, 1, 19, 10, 17, 9, 15, 8, 13, 7, 11, 6, 20, 11, 9, 5, 16, 9, 7, 4, 19, 11, 12, 7, 17, 10, 5, 3, 18, 11, 13, 8, 8, 5, 19, 12, 11, 7, 14, 9, 17, 11, 20, 13, 3, 2, 19, 13, 16, 11, 13, 9, 10, 7, 17, 12, 7, 5, 18, 13, 11, 8, 15, 11, 19, 14, 4, 3, 17, 13, 13, 10, 9, 7, 14, 11, 19, 15, 5, 4, 16, 13, 11, 9, 17, 14, 6, 5, 19, 16, 13, 11, 20, 17, 7, 6, 15, 13, 8, 7, 17, 15, 9, 8, 19, 17, 10, 9, 11, 10, 12, 11, 13, 12, 14, 13, 15, 14, 16, 15, 17, 16, 18, 17, 19, 18, 20, 19, 1, 1, 19, 20, 18, 19, 17, 18, 16, 17, 15, 16, 14, 15, 13, 14, 12, 13, 11, 12, 10, 11, 9, 10, 17, 19, 8, 9, 15, 17, 7, 8, 13, 15, 6, 7, 17, 20, 11, 13, 16, 19, 5, 6, 14, 17, 9, 11, 13, 16, 4, 5, 15, 19, 11, 14, 7, 9, 10, 13, 13, 17, 3, 4, 14, 19, 11, 15, 8, 11, 13, 18, 5, 7, 12, 17, 7, 10, 9, 13, 11, 16, 13, 19, 2, 3, 13, 20, 11, 17, 9, 14, 7, 11, 12, 19, 5, 8, 8, 13, 11, 18, 3, 5, 10, 17, 7, 12, 11, 19, 4, 7, 9, 16, 5, 9, 11, 20, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 1, 2, 9, 19, 8, 17, 7, 15, 6, 13, 5, 11, 9, 20, 4, 9, 7, 16, 3, 7, 8, 19, 5, 12, 7, 17, 2, 5, 7, 18, 5, 13, 3, 8, 7, 19, 4, 11, 5, 14, 6, 17, 7, 20, 1, 3, 6, 19, 5, 16, 4, 13, 3, 10, 5, 17, 2, 7, 5, 18, 3, 11, 4, 15, 5, 19, 1, 4};/*! * @brief Set PP input address. * @param ptr The pointer to the Y value of input * @return Zero on success, others on failure */int pp_ptr(unsigned long ptr){ g_pp_cfg.ptr.y = ptr; g_pp_cfg.ptr.u = g_pp_cfg.ptr.v = g_pp_cfg.ptr.qp = 0; return pphw_ptr(&g_pp_cfg);}/*! * @brief Enable or disable PP. * @param flag Zero to disable PP, others to enable PP * @return Zero on success, others on failure */int pp_enable(int flag){ return pphw_enable(flag);}/*! * @brief Get the display No. of last completed PP frame. * @return The display No. of last completed PP frame. */int pp_num_last(void){ return (g_disp_num ? 0 : 1);}/*! * @brief Initialize PP. * @param vout Pointer to _vout_data structure * @return Zero on success, others on failure */int pp_init(vout_data * vout){ pphw_init(); pphw_enable(0); enable_irq(INT_EMMAPP); return request_irq(INT_EMMAPP, pp_isr, 0, pp_dev, vout);}/*! * @brief Deinitialize PP. * @param vout Pointer to _vout_data structure */void pp_exit(vout_data * vout){ disable_irq(INT_EMMAPP); free_irq(INT_EMMAPP, vout); pphw_enable(0); pphw_exit();}/*! * @brief Configure PP. * @param vout Pointer to _vout_data structure * @return Zero on success, others on failure */int pp_cfg(vout_data * vout){ if (!vout) return -1; /* PP accepts YUV420 input only */ if (vout->v2f.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420) { pr_debug("unsupported pixel format.\n"); return -1; } g_pp_cfg.operation = 0; memset(g_pp_cfg.csc_table, 0, sizeof(g_pp_cfg.csc_table)); /* Convert output pixel format to PP required format */ switch (vout->v4l2_fb.fmt.pixelformat) { case V4L2_PIX_FMT_BGR32: g_pp_cfg.red_width = 8; g_pp_cfg.green_width = 8; g_pp_cfg.blue_width = 8; g_pp_cfg.red_offset = 8; g_pp_cfg.green_offset = 16; g_pp_cfg.blue_offset = 24; g_pp_cfg.rgb_resolution = 32; break; case V4L2_PIX_FMT_RGB32: g_pp_cfg.red_width = 8; g_pp_cfg.green_width = 8; g_pp_cfg.blue_width = 8; g_pp_cfg.red_offset = 24; g_pp_cfg.green_offset = 16; g_pp_cfg.blue_offset = 8; g_pp_cfg.rgb_resolution = 32; break; case V4L2_PIX_FMT_YUYV: g_pp_cfg.red_width = 0; g_pp_cfg.green_width = 0; g_pp_cfg.blue_width = 0; g_pp_cfg.red_offset = 0; g_pp_cfg.green_offset = 0; g_pp_cfg.blue_offset = PP_PIX_YUYV; g_pp_cfg.rgb_resolution = 16; break; case V4L2_PIX_FMT_UYVY: g_pp_cfg.red_width = 0; g_pp_cfg.green_width = 0; g_pp_cfg.blue_width = 0; g_pp_cfg.red_offset = 0; g_pp_cfg.green_offset = 0; g_pp_cfg.blue_offset = PP_PIX_UYVY; g_pp_cfg.rgb_resolution = 16; break; case V4L2_PIX_FMT_RGB565: default: g_pp_cfg.red_width = 5; g_pp_cfg.green_width = 6; g_pp_cfg.blue_width = 5; g_pp_cfg.red_offset = 11; g_pp_cfg.green_offset = 5; g_pp_cfg.blue_offset = 0; g_pp_cfg.rgb_resolution = 16; break; } if (vout->ipu_buf[0] != -1) g_pp_cfg.ptr.y = (unsigned int)vout->queue_buf_paddr[vout->ipu_buf[0]]; else g_pp_cfg.ptr.y = 0; g_pp_cfg.ptr.u = g_pp_cfg.ptr.v = g_pp_cfg.ptr.qp = 0; g_pp_cfg.dim.in.width = vout->v2f.fmt.pix.width; g_pp_cfg.dim.in.height = vout->v2f.fmt.pix.height; g_pp_cfg.dim.out.width = vout->crop_current.width; g_pp_cfg.dim.out.height = vout->crop_current.height; g_pp_cfg.dim.num.width = 0; g_pp_cfg.dim.num.height = 0; g_pp_cfg.dim.den.width = 0; g_pp_cfg.dim.den.height = 0; if (scale_2d(&g_pp_cfg.dim)) { pr_debug("unsupported resize ratio.\n"); return -1; } g_pp_cfg.dim.out.width = vout->crop_current.width; g_pp_cfg.dim.out.height = vout->crop_current.height; g_pp_cfg.in_y_stride = 0; if (set_output_addr(&g_pp_cfg, vout)) { pr_debug("failed to set pp output address.\n"); return -1; } return pphw_cfg(&g_pp_cfg);}irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id);/*! * @brief PP IRQ handler. */static irqreturn_t pp_isr(int irq, void *dev_id){ int status; vout_data *vout = dev_id; status = pphw_isr(); if ((status & 0x1) == 0) { /* Not frame complete interrupt */ pr_debug("not pp frame complete interrupt\n"); return IRQ_HANDLED; } if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) { g_disp_num = g_disp_num ? 0 : 1; g_pp_cfg.outptr = (unsigned int)vout->display_bufs[g_disp_num]; pphw_outptr(&g_pp_cfg); } return mxc_v4l2out_pp_in_irq_handler(irq, dev_id);}/*! * @brief Set PP output address. * @param cfg Pointer to emma_pp_cfg structure * @param vout Pointer to _vout_data structure * @return Zero on success, others on failure */static int set_output_addr(emma_pp_cfg * cfg, vout_data * vout){ if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) { g_disp_num = 0; cfg->outptr = (unsigned int)vout->display_bufs[g_disp_num]; cfg->out_stride = vout->crop_current.width; return 0; } else { struct fb_info *fb; fb = registered_fb[vout->output_fb_num[vout->cur_disp_output]]; if (!fb) return -1; cfg->outptr = fb->fix.smem_start; cfg->outptr += vout->crop_current.top * fb->var.xres_virtual * (fb->var.bits_per_pixel >> 3) + vout->crop_current.left * (fb->var.bits_per_pixel >> 3); cfg->out_stride = fb->var.xres_virtual; return 0; }}/*! * @brief Get maximum common divisor. * @param x First input value * @param y Second input value * @return Maximum common divisor of x and y */static int gcd(int x, int y){ int k; if (x < y) { k = x; x = y; y = k; } while ((k = x % y)) { x = y; y = k; } return y;}/*! * @brief Get ratio. * @param x First input value * @param y Second input value * @param den Denominator of the ratio (corresponding to y) * @return Numerator of the ratio (corresponding to x) */static int ratio(int x, int y, int *den){ int g; if (!x || !y) return 0; g = gcd(x, y); *den = y / g; return x / g;}/*! * @brief Build PP coefficient entry * Build one or more coefficient entries for PP coefficient table based * on given coefficient. * * @param k The index of the coefficient in coefficient table * @param coeff The weighting coefficient * @param base The base of the coefficient * @param nxt Number of pixels to be read * * @return The index of the next coefficient entry on success * -1 on failure */static int scale_0d(int k, int coeff, int base, int nxt){ if (k >= PP_TBL_MAX) { /* no more space in table */ pr_debug("no space in scale table, k = %d\n", k); return -1; } coeff = ((coeff << BC_COEF) + (base >> 1)) / base; /* * Valid values for weighting coefficient are 0, 2 to 30, and 31. * A value of 31 is treated as 32 and therefore 31 is an * invalid co-efficient. */ if (coeff >= SZ_COEF - 1) coeff--; else if (coeff == 1) coeff++; coeff = coeff << BC_NXT; if (nxt < SZ_NXT) { coeff |= nxt; coeff <<= 1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -