?? mx27_prphw.c
字號:
/* * Copyright 2004-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_prphw.c * * @brief MX27 Video For Linux 2 capture driver * * @ingroup MXC_V4L2_CAPTURE */#include <linux/kernel.h>#include <linux/module.h>#include <linux/string.h>#include <linux/clk.h>#include <asm/io.h>#include <linux/delay.h>#include "mx27_prp.h"#define PRP_MIN_IN_WIDTH 32#define PRP_MAX_IN_WIDTH 2044#define PRP_MIN_IN_HEIGHT 32#define PRP_MAX_IN_HEIGHT 2044typedef struct _coeff_t { unsigned long coeff[2]; unsigned long cntl;} coeff_t[2][2];static coeff_t *PRP_RSZ_COEFF = (coeff_t *) PRP_CH1_RZ_HORI_COEF1;static unsigned char scale_get(scale_t * t, unsigned char *i, unsigned char *out);static int gcd(int x, int y);static int ratio(int x, int y, int *den);static int prp_scale_bilinear(scale_t * t, int coeff, int base, int nxt);static int prp_scale_ave(scale_t * t, unsigned char base);static int ave_scale(scale_t * t, int inv, int outv);static int scale(scale_t * t, int inv, int outv);#define PRP_DUMP(val) pr_debug("%s\t = 0x%08X\t%d\n", #val, __raw_readl(val), __raw_readl(val))static void prp_dump(void){ PRP_DUMP(PRP_CNTL); PRP_DUMP(PRP_INTRCNTL); PRP_DUMP(PRP_INTRSTATUS); PRP_DUMP(PRP_SOURCE_Y_PTR); PRP_DUMP(PRP_SOURCE_CB_PTR); PRP_DUMP(PRP_SOURCE_CR_PTR); PRP_DUMP(PRP_DEST_RGB1_PTR); PRP_DUMP(PRP_DEST_RGB2_PTR); PRP_DUMP(PRP_DEST_Y_PTR); PRP_DUMP(PRP_DEST_CB_PTR); PRP_DUMP(PRP_DEST_CR_PTR); PRP_DUMP(PRP_SOURCE_FRAME_SIZE); PRP_DUMP(PRP_CH1_LINE_STRIDE); PRP_DUMP(PRP_SRC_PIXEL_FORMAT_CNTL); PRP_DUMP(PRP_CH1_PIXEL_FORMAT_CNTL); PRP_DUMP(PRP_CH1_OUT_IMAGE_SIZE); PRP_DUMP(PRP_CH2_OUT_IMAGE_SIZE); PRP_DUMP(PRP_SOURCE_LINE_STRIDE); PRP_DUMP(PRP_CSC_COEF_012); PRP_DUMP(PRP_CSC_COEF_345); PRP_DUMP(PRP_CSC_COEF_678); PRP_DUMP(PRP_CH1_RZ_HORI_COEF1); PRP_DUMP(PRP_CH1_RZ_HORI_COEF2); PRP_DUMP(PRP_CH1_RZ_HORI_VALID); PRP_DUMP(PRP_CH1_RZ_VERT_COEF1); PRP_DUMP(PRP_CH1_RZ_VERT_COEF2); PRP_DUMP(PRP_CH1_RZ_VERT_VALID); PRP_DUMP(PRP_CH2_RZ_HORI_COEF1); PRP_DUMP(PRP_CH2_RZ_HORI_COEF2); PRP_DUMP(PRP_CH2_RZ_HORI_VALID); PRP_DUMP(PRP_CH2_RZ_VERT_COEF1); PRP_DUMP(PRP_CH2_RZ_VERT_COEF2); PRP_DUMP(PRP_CH2_RZ_VERT_VALID);}/*! * @param t table * @param i table index * @param out bilinear # input pixels to advance * average whether result is ready for output * @return coefficient*/static unsigned char scale_get(scale_t * t, unsigned char *i, unsigned char *out){ unsigned char c; c = t->tbl[*i]; (*i)++; *i %= t->len; if (out) { if (t->algo == ALGO_BIL) { for ((*out) = 1; (*i) && ((*i) < t->len) && !t->tbl[(*i)]; (*i)++) { (*out)++; } if ((*i) == t->len) (*i) = 0; } else *out = c >> BC_COEF; } c &= SZ_COEF - 1; if (c == SZ_COEF - 1) c = SZ_COEF; return c;}/*! * @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 PrP coefficient entry based on bilinear algorithm * * @param t The pointer to scale_t structure * @param coeff The weighting coefficient * @param base The base of the coefficient * @param nxt Number of pixels to be read * * @return The length of current coefficient table on success * -1 on failure */static int prp_scale_bilinear(scale_t * t, int coeff, int base, int nxt){ int i; if (t->len >= sizeof(t->tbl)) return -1; coeff = ((coeff << BC_COEF) + (base >> 1)) / base; if (coeff >= SZ_COEF - 1) coeff--; coeff |= SZ_COEF; t->tbl[(int)t->len++] = (unsigned char)coeff; for (i = 1; i < nxt; i++) { if (t->len >= MAX_TBL) return -1; t->tbl[(int)t->len++] = 0; } return t->len;}#define _bary(name) static const unsigned char name[]_bary(c1) = {7};_bary(c2) = {4, 4};_bary(c3) = {2, 4, 2};_bary(c4) = {2, 2, 2, 2};_bary(c5) = {1, 2, 2, 2, 1};_bary(c6) = {1, 1, 2, 2, 1, 1};_bary(c7) = {1, 1, 1, 2, 1, 1, 1};_bary(c8) = {1, 1, 1, 1, 1, 1, 1, 1};_bary(c9) = {1, 1, 1, 1, 1, 1, 1, 1, 0};_bary(c10) = {0, 1, 1, 1, 1, 1, 1, 1, 1, 0};_bary(c11) = {0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0};_bary(c12) = {0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0};_bary(c13) = {0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0};_bary(c14) = {0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0};_bary(c15) = {0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0};_bary(c16) = {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};_bary(c17) = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};_bary(c18) = {0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0};_bary(c19) = {0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0};_bary(c20) = {0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0};static const unsigned char *ave_coeff[] = { c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20};static const unsigned char coeftab[] = { 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, 4, 17, 3, 13, 2, 9, 3, 14, 4, 19, 1, 5, 3, 16, 2, 11, 3, 17, 1, 6, 3, 19, 2, 13, 3, 20, 1, 7, 2, 15, 1, 8, 2, 17, 1, 9, 2, 19, 1, 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, 16, 1, 17, 1, 18, 1, 19, 1, 20};/*! * @brief Build PrP coefficient table based on average algorithm * * @param t The pointer to scale_t structure * @param base The base of the coefficient * * @return The length of current coefficient table on success * -1 on failure */static int prp_scale_ave(scale_t * t, unsigned char base){ if (t->len + base > sizeof(t->tbl)) return -1; memcpy(&t->tbl[(int)t->len], ave_coeff[(int)base - 1], base); t->len = (unsigned char)(t->len + base); t->tbl[t->len - 1] |= SZ_COEF; return t->len;}/*! * @brief Build PrP coefficient table based on average algorithm * * @param t The pointer to scale_t structure * @param inv Input resolution * @param outv Output resolution * * @return The length of current coefficient table on success * -1 on failure */static int ave_scale(scale_t * t, int inv, int outv){ int ratio_count; ratio_count = 0; if (outv != 1) { unsigned char a[20]; int v; /* split n:m into multiple n[i]:1 */ for (v = 0; v < outv; v++) a[v] = (unsigned char)(inv / outv); inv %= outv; if (inv) { /* find start of next layer */ v = (outv - inv) >> 1; inv += v; for (; v < inv; v++) a[v]++; } for (v = 0; v < outv; v++) { if (prp_scale_ave(t, a[v]) < 0) return -1; t->ratio[ratio_count] = a[v]; ratio_count++; } } else if (prp_scale_ave(t, inv) < 0) { return -1; } else { t->ratio[ratio_count++] = (char)inv; ratio_count++; } return t->len;}/*! * @brief Build PrP coefficient table * * @param t The pointer to scale_t structure * @param inv input resolution reduced ratio * @param outv output resolution reduced ratio * * @return The length of current coefficient table on success * -1 on failure */static int scale(scale_t * t, int inv, int outv){ int v; /* overflow counter */ int coeff, nxt; /* table output */ t->len = 0; if (t->algo == ALGO_AUTO) { /* automatic choice - bilinear for shrinking less than 2:1 */ t->algo = ((outv != inv) && ((2 * outv) > inv)) ? ALGO_BIL : ALGO_AVG; } /* 1:1 resize must use averaging, bilinear will hang */ if ((inv == outv) && (t->algo == ALGO_BIL)) { pr_debug("Warning: 1:1 resize must use averaging algo\n"); t->algo = ALGO_AVG; } memset(t->tbl, 0, sizeof(t->tbl)); if (t->algo == ALGO_BIL) { t->ratio[0] = (char)inv; t->ratio[1] = (char)outv; } else memset(t->ratio, 0, sizeof(t->ratio)); if (inv == outv) { /* force scaling */ t->ratio[0] = 1; if (t->algo == ALGO_BIL) t->ratio[1] = 1; return prp_scale_ave(t, 1); } if (inv < outv) { pr_debug("Upscaling not supported %d:%d\n", inv, outv); return -1; } if (t->algo != ALGO_BIL) return ave_scale(t, inv, outv); v = 0; if (inv >= 2 * outv) { /* downscale: >=2:1 bilinear approximation */ coeff = inv - 2 * outv; v = 0; nxt = 0; do { v += coeff; nxt = 2; while (v >= outv) { v -= outv; nxt++; } if (prp_scale_bilinear(t, 1, 2, nxt) < 0) return -1; } while (v); } else { /* downscale: bilinear */ int in_pos_inc = 2 * outv; int out_pos = inv; int out_pos_inc = 2 * inv; int init_carry = inv - outv; int carry = init_carry; v = outv + in_pos_inc; do { coeff = v - out_pos; out_pos += out_pos_inc; carry += out_pos_inc; for (nxt = 0; v < out_pos; nxt++) { v += in_pos_inc; carry -= in_pos_inc; } if (prp_scale_bilinear(t, coeff, in_pos_inc, nxt) < 0) return -1; } while (carry != init_carry); } return t->len;}/*! * @brief Get approximate ratio * * @param pscale The pointer to scale_t structure which holdes * coefficient tables * @param mt Scale ratio numerator * @param nt Scale ratio denominator * @param *n denominator of approximate ratio * @return numerator of approximate ratio */static int approx_ratio(int mt, int nt, int *n){ int index = sizeof(coeftab) / sizeof(coeftab[0]) / 2; int left = 0; int right = index - 1; int nom, den; while (index > 0) { nom = coeftab[(((right + left) >> 1) << 1) + 1]; den = coeftab[(((right + left) >> 1) << 1)]; if ((nom * nt - mt * den) < 0) { left = (right + left) >> 1; } else { right = (right + left) >> 1; } index = index >> 1; } *n = coeftab[left * 2]; nom = coeftab[left * 2 + 1]; return nom;}/*! * @brief Build PrP coefficient table * * @param pscale The pointer to scale_t structure which holdes * coefficient tables * @param din Scale ratio numerator * @param dout Scale ratio denominator * @param inv Input resolution * @param vout Output resolution * @param pout Internal output resolution * @param retry Retry times (round the output length) when need * * @return Zero on success, others on failure */int prp_scale(scale_t * pscale, int din, int dout, int inv, unsigned short *vout, unsigned short *pout, int ch){ int num, new_num; int den, new_den; unsigned short outv; /* auto-generation of values */ if (!(dout && din)) { if (!*vout) dout = din = 1; else { din = inv; dout = *vout; } } if (din < dout) { pr_debug("Scale err, unsupported ratio %d : %d\n", din, dout); return -1; } num = ratio(din, dout, &den); if (!num) { pr_debug("Scale err, unsupported ratio %d : %d\n", din, dout); return -1; } if (num > MAX_TBL) { if (num / den <= MAX_TBL) { new_num = approx_ratio(num, den, &new_den); num = new_num; den = new_den; } else if (ch == PRP_CHANNEL_2) { pr_debug("Unsupported ch_2 resize ratio %d : %d\n", num, den); return -1; } else if (num / den > MAX_TBL * MAX_TBL) { pr_debug("Unsupported ch_1 resize ratio %d : %d\n", num, den); return -1; } } if ((num > MAX_TBL * MAX_TBL) || scale(pscale, num, den) < 0) { pr_debug("Scale err, unsupported ratio %d : %d\n", num, den); return -1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -