?? mx27_pp.c
字號:
coeff |= 1; } else { /* * src inc field is 2 bit wide, for 4+, use special * code 0:0:1 to prevent dest inc */ coeff |= PP_SKIP; coeff <<= 1; coeff |= 1; nxt -= PP_SKIP; do { pr_debug("tbl = %03X\n", coeff); scale_tbl[k++] = coeff; coeff = (nxt > PP_SKIP) ? PP_SKIP : nxt; coeff <<= 1; } while ((nxt -= PP_SKIP) > 0); } pr_debug("tbl = %03X\n", coeff); scale_tbl[k++] = coeff; return k;}/*! * @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(pp_coeftab) / sizeof(pp_coeftab[0]) / 2; int left = 0; int right = index - 1; int nom = 0, den = 0; while (index > 0) { nom = pp_coeftab[(((right + left) >> 1) << 1)]; den = pp_coeftab[(((right + left) >> 1) << 1) + 1]; if ((nom * nt - mt * den) > 0) { left = (right + left) >> 1; } else { right = (right + left) >> 1; } index = index >> 1; } *n = pp_coeftab[right * 2 + 1]; nom = pp_coeftab[right * 2]; return nom;}/* * @brief Build PP coefficient table * Build PP coefficient table for one dimension (width or height) * based on given input and output resolution * * @param inv input resolution * @param outv output resolution * @param k index of free table entry * * @return The index of the next free coefficient entry on success * -1 on failure */static int scale_1d(int inv, int outv, int k){ int v; /* overflow counter */ int coeff, nxt; /* table output */ if (inv == outv) return scale_0d(k, 1, 1, 1); /* force scaling */ v = 0; if (inv < outv) { /* upscale: mix <= 2 input pixels per output pixel */ do { coeff = outv - v; v += inv; if (v >= outv) { v -= outv; nxt = 1; } else nxt = 0; pr_debug("upscale: coeff = %d/%d nxt = %d\n", coeff, outv, nxt); k = scale_0d(k, coeff, outv, nxt); if (k < 0) return -1; } while (v); } else if (inv >= 2 * outv) { /* PP doesn't support resize ratio > 2:1 except 4:1. */ if ((inv != 2 * outv) && (inv != 4 * outv)) return -1; /* downscale: >=2:1 bilinear approximation */ coeff = inv - 2 * outv; v = 0; nxt = 0; do { v += coeff; nxt = 2; while (v >= outv) { v -= outv; nxt++; } pr_debug("downscale: coeff = 1/2 nxt = %d\n", nxt); k = scale_0d(k, 1, 2, nxt); if (k < 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; } pr_debug("downscale: coeff = %d/%d nxt = %d\n", coeff, in_pos_inc, nxt); k = scale_0d(k, coeff, in_pos_inc, nxt); if (k < 0) return -1; } while (carry != init_carry); } return k;}/* * @brief Build PP coefficient table * Build PP coefficient table for one dimension (width or height) * based on given input and output resolution. The given input * and output resolution might be not supported due to hardware * limits. In this case this functin rounds the input and output * to closest possible values and return them to caller. * * @param inv input resolution, might be modified after the call * @param outv output resolution, might be modified after the call * @param k index of free table entry * * @return The index of the next free coefficient entry on success * -1 on failure */static int scale_1d_smart(int *inv, int *outv, int index){ int len, num, den, approx_num, approx_den; static int num1, den1; if (!inv || !outv) return -1; /* Both should be non-zero */ if (!(*inv) || !(*outv)) return -1; if ((*outv > 4 * (*inv)) || ((*inv > 2 * (*outv)) && (*inv != 4 * (*outv)))) { pr_debug("unsupported pp resize ration: inv/outv = %d/%d\n", *inv, *outv); return -1; } num = ratio(*inv, *outv, &den); if (index == 0) { if ((num > 20) || (den > 20)) { approx_num = approx_ratio(num, den, &approx_den); num = approx_num; den = approx_den; } } else { if ((num > (40 - index)) || (den > (40 - index))) { approx_num = approx_ratio(num, den, &approx_den); num = approx_num; den = approx_den; } if ((num == num1) && (den == den1)) { return index; } } if ((len = scale_1d(num, den, index)) < 0) { return -1; } else { if (index == 0) { num1 = num; den1 = den; } return len; }}/* * @brief Build PP coefficient table for both width and height * Build PP coefficient table for both width and height based on * given resizing ratios. * * @param sz Structure contains resizing ratio informations * * @return 0 on success, others on failure */static int scale_2d(emma_pp_scale * sz){ int inv, outv; /* horizontal resizing. parameter check - must provide in size */ if (!sz->in.width) return -1; /* Resizing based on num:den */ inv = sz->num.width; outv = sz->den.width; if ((g_hlen = scale_1d_smart(&inv, &outv, 0)) > 0) { /* Resizing succeeded */ sz->den.width = outv; sz->out.width = (sz->in.width * outv) / inv; } else { /* Resizing based on in:out */ inv = sz->in.width; outv = sz->out.width; if ((g_hlen = scale_1d_smart(&inv, &outv, 0)) > 0) { /* Resizing succeeded */ sz->out.width = outv; sz->num.width = ratio(sz->in.width, sz->out.width, &sz->den.width); } else return -1; } sz->out.width &= ~1; /* vertical resizing. parameter check - must provide in size */ if (!sz->in.height) return -1; /* Resizing based on num:den */ inv = sz->num.height; outv = sz->den.height; if ((g_vlen = scale_1d_smart(&inv, &outv, g_hlen)) > 0) { /* Resizing succeeded */ sz->den.height = outv; sz->out.height = (sz->in.height * outv) / inv; } else { /* Resizing based on in:out */ inv = sz->in.height; outv = sz->out.height; if ((g_vlen = scale_1d_smart(&inv, &outv, g_hlen)) > 0) { /* Resizing succeeded */ sz->out.height = outv; sz->num.height = ratio(sz->in.height, sz->out.height, &sz->den.height); } else return -1; } return 0;}/*! * @brief Set PP resizing registers. * @param sz Pointer to pp scaling structure * @return Zero on success, others on failure */static int pphw_scale(emma_pp_scale * sz){ __raw_writel((sz->out.width << 16) | sz->out.height, PP_DEST_IMAGE_SIZE); __raw_writel(((g_hlen - 1) << 16) | (g_vlen == g_hlen ? 0 : (g_hlen << 8)) | (g_vlen - 1), PP_RESIZE_INDEX); for (g_hlen = 0; g_hlen < g_vlen; g_hlen++) __raw_writel(scale_tbl[g_hlen], PP_RESIZE_COEF_TBL + g_hlen * 4); return 0;}/*! * @brief Reset PP. * @return Zero on success, others on failure */static int pphw_reset(void){ int i; __raw_writel(0x100, PP_CNTL); /* timeout */ for (i = 0; i < 1000; i++) { if (!(__raw_readl(PP_CNTL) & 0x100)) { pr_debug("pp reset over\n"); break; } } /* check reset value */ if (__raw_readl(PP_CNTL) != 0x876) { pr_debug("pp reset value err = 0x%08X\n", __raw_readl(PP_CNTL)); return -1; } return 0;}/*! * @brief Enable or disable PP. * @param flag Zero to disable PP, others to enable PP * @return Zero on success, others on failure */static int pphw_enable(int flag){ int ret = 0; if (flag) __raw_writel(__raw_readl(PP_CNTL) | 1, PP_CNTL); else ret = pphw_reset(); return ret;}/*! * @brief Set PP input address. * @param cfg The pointer to PP configuration parameter * @return Zero on success, others on failure */static int pphw_ptr(emma_pp_cfg * cfg){ if (!cfg->ptr.u) { int size; /* yuv - packed */ size = PP_CALC_Y_SIZE(cfg); cfg->ptr.u = cfg->ptr.y + size; cfg->ptr.v = cfg->ptr.u + (size >> 2); /* yuv packed with qp appended */ if (!cfg->ptr.qp) cfg->ptr.qp = cfg->ptr.v + (size >> 2); } __raw_writel(cfg->ptr.y, PP_SOURCE_Y_PTR); __raw_writel(cfg->ptr.u, PP_SOURCE_CB_PTR); __raw_writel(cfg->ptr.v, PP_SOURCE_CR_PTR); __raw_writel(cfg->ptr.qp, PP_QUANTIZER_PTR); return 0;}/*! * @brief Set PP output address. * @param cfg The pointer to PP configuration parameter * @return Zero on success, others on failure */static int pphw_outptr(emma_pp_cfg * cfg){ __raw_writel(cfg->outptr, PP_DEST_RGB_PTR); return 0;}/*! * @brief Configuration PP. * @param cfg The pointer to PP configuration parameter * @return Zero on success, others on failure */static int pphw_cfg(emma_pp_cfg * cfg){ int rt; register int r; pphw_scale(&cfg->dim); if (!cfg->in_y_stride) cfg->in_y_stride = cfg->dim.in.width; if (!cfg->out_stride) cfg->out_stride = cfg->dim.out.width; r = __raw_readl(PP_CNTL) & ~EN_MASK; /* config parms */ r |= cfg->operation & EN_MASK; if (cfg->operation & EN_MACROBLOCK) { /* Macroblock Mode */ r |= 0x0200; __raw_writel(0x06, PP_INTRCNTL); } else { /* Frame mode */ __raw_writel(0x05, PP_INTRCNTL); } if (cfg->red_width | cfg->green_width | cfg->blue_width) { /* color conversion to be performed */ r |= EN_CSC; if (!(cfg->red_offset | cfg->green_offset)) { /* auto offset B:G:R LSb to Msb */ cfg->green_offset = cfg->blue_offset + cfg->blue_width; cfg->red_offset = cfg->green_offset + cfg->green_width; } if (!cfg->rgb_resolution) { /* derive minimum resolution required */ int w, w2; w = cfg->red_offset + cfg->red_width; w2 = cfg->blue_offset + cfg->blue_width; if (w < w2) w = w2; w2 = cfg->green_offset + cfg->green_width; if (w < w2) w = w2; if (w > 16) w = 24; else if (w > 8) w = 16; else w = 8; cfg->rgb_resolution = w; } /* 00,11 - 32 bpp, 10 - 16 bpp, 01 - 8 bpp */ r &= ~0xC00; if (cfg->rgb_resolution < 32) r |= (cfg->rgb_resolution << 7); __raw_writel((cfg->red_offset << 26) | (cfg->green_offset << 21) | (cfg->blue_offset << 16) | (cfg->red_width << 8) | (cfg->green_width << 4) | cfg->blue_width, PP_DEST_FRAME_FMT_CNTL); } else { /* add YUV422 formatting */ static const unsigned int _422[] = { 0x62000888, 0x60100888, 0x43080888, 0x41180888 }; __raw_writel(_422[(cfg->blue_offset >> 3) & 3], PP_DEST_FRAME_FMT_CNTL); cfg->rgb_resolution = 16; r &= ~0xC00; r |= (cfg->rgb_resolution << 7); } /* add csc formatting */ if (!cfg->csc_table[1]) { static const unsigned short _csc[][6] = { {0x80, 0xb4, 0x2c, 0x5b, 0x0e4, 0}, {0x95, 0xcc, 0x32, 0x68, 0x104, 1}, {0x80, 0xca, 0x18, 0x3c, 0x0ec, 0}, {0x95, 0xe5, 0x1b, 0x44, 0x10e, 1}, }; memcpy(cfg->csc_table, _csc[cfg->csc_table[0]], sizeof(_csc[0])); } __raw_writel((cfg->csc_table[0] << 24) | (cfg->csc_table[1] << 16) | (cfg->csc_table[2] << 8) | cfg->csc_table[3], PP_CSC_COEF_0123); __raw_writel((cfg->csc_table[5] ? (1 << 9) : 0) | cfg->csc_table[4], PP_CSC_COEF_4); __raw_writel(r, PP_CNTL); pphw_ptr(cfg); pphw_outptr(cfg); /* * #MB in a row = input_width / 16pix * 1 byte per QP per MB * QP must be formatted to be 4-byte aligned * YUV lines are to be 4-byte aligned as well * So Y is 8 byte aligned, as U = V = Y/2 for 420 * MPEG MBs are 16x16 anyway */ __raw_writel((cfg->dim.in.width << 16) | cfg->dim.in.height, PP_PROCESS_FRAME_PARA); __raw_writel(cfg->in_y_stride | (PP_CALC_QP_WIDTH(cfg) << 16), PP_SOURCE_FRAME_WIDTH); /* in bytes */ rt = cfg->rgb_resolution >> 3; if (rt == 3) rt = 4; __raw_writel(cfg->out_stride * rt, PP_DEST_DISPLAY_WIDTH); pp_dump(); return 0;}/*! * @brief Check PP interrupt status. * @return PP interrupt status */static int pphw_isr(void){ unsigned long status; pr_debug("pp: in isr.\n"); status = __raw_readl(PP_INTRSTATUS) & 7; if (!status) { pr_debug("pp: not my isr err.\n"); return status; } if (status & 4) pr_debug("pp: isr state error.\n"); /* clear interrupt status */ __raw_writel(status, PP_INTRSTATUS); return status;}static struct clk *emma_clk;/*! * @brief PP module clock enable */static void pphw_init(void){ emma_clk = clk_get(NULL, "emma_clk"); clk_enable(emma_clk);}/*! * @brief PP module clock disable */static void pphw_exit(void){ clk_disable(emma_clk); clk_put(emma_clk);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -