?? mx27_prphw.c
} if (pscale->algo == ALGO_BIL) { unsigned char i, j, k; outv = (unsigned short)(inv / pscale->ratio[0] * pscale->ratio[1]); inv %= pscale->ratio[0]; for (i = j = 0; inv > 0; j++) { unsigned char nxt; k = scale_get(pscale, &i, &nxt); if (inv == 1 && k < SZ_COEF) { /* needs 2 pixels for this output */ break; } inv -= nxt; } outv = outv + j; } else { unsigned char i, tot; for (tot = i = 0; pscale->ratio[i]; i++) tot = tot + pscale->ratio[i]; outv = (unsigned short)(inv / tot) * i; inv %= tot; for (i = 0; inv > 0; i++, outv++) inv -= pscale->ratio[i]; } if (!(*vout) || ((*vout) > outv)) *vout = outv; if (pout) *pout = outv; return 0;}/*! * @brief Reset PrP block */int prphw_reset(void){ unsigned long val; unsigned long flag; int i; flag = PRP_CNTL_RST; val = PRP_CNTL_RSTVAL; __raw_writel(flag, PRP_CNTL); /* timeout */ for (i = 0; i < 1000; i++) { if (!(__raw_readl(PRP_CNTL) & flag)) { pr_debug("PrP reset over\n"); break; } msleep(1); } /* verify reset value */ if (__raw_readl(PRP_CNTL) != val) { pr_info("PrP reset err, val = 0x%08X\n", __raw_readl(PRP_CNTL)); return -1; } return 0;}/*! * @brief Enable PrP channel. * @param channel Channel number to be enabled * @return Zero on success, others on failure */int prphw_enable(int channel){ unsigned long val; val = __raw_readl(PRP_CNTL); if (channel & PRP_CHANNEL_1) val |= PRP_CNTL_CH1EN; if (channel & PRP_CHANNEL_2) val |= (PRP_CNTL_CH2EN | PRP_CNTL_CH2_FLOWEN | PRP_CNTL_AUTODROP); __raw_writel(val, PRP_CNTL); return 0;}/*! * @brief Disable PrP channel. * @param channel Channel number to be disable * @return Zero on success, others on failure */int prphw_disable(int channel){ unsigned long val; val = __raw_readl(PRP_CNTL); if (channel & PRP_CHANNEL_1) val &= ~PRP_CNTL_CH1EN; if (channel & PRP_CHANNEL_2) val &= ~(PRP_CNTL_CH2EN | PRP_CNTL_CH2_FLOWEN); __raw_writel(val, PRP_CNTL); return 0;}/*! * @brief Set PrP input buffer address. * @param cfg Pointer to PrP configuration parameter * @return Zero on success, others on failure */int prphw_inptr(emma_prp_cfg * cfg){ if (cfg->in_csi & PRP_CSI_EN) return -1; __raw_writel(cfg->in_ptr, PRP_SOURCE_Y_PTR); if (cfg->in_pix == PRP_PIXIN_YUV420) { size = cfg->in_line_stride * cfg->in_height; __raw_writel(cfg->in_ptr + size, PRP_SOURCE_CB_PTR); __raw_writel(cfg->in_ptr + size + (size >> 2), PRP_SOURCE_CR_PTR); } return 0;}/*! * @brief Set PrP channel 1 output buffer 1 address. * @param cfg Pointer to PrP configuration parameter * @return Zero on success, others on failure */int prphw_ch1ptr(emma_prp_cfg * cfg){ if (cfg->ch1_pix == PRP_PIX1_UNUSED) return -1; __raw_writel(cfg->ch1_ptr, PRP_DEST_RGB1_PTR); /* support double buffer in loop mode only */ if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) { if (cfg->ch1_ptr2) __raw_writel(cfg->ch1_ptr2, PRP_DEST_RGB2_PTR); else __raw_writel(cfg->ch1_ptr, PRP_DEST_RGB2_PTR); } return 0;}/*! * @param cfg Pointer to PrP configuration parameter * @return Zero on success, others on failure */int prphw_ch1ptr2(emma_prp_cfg * cfg){ if (cfg->ch1_pix == PRP_PIX1_UNUSED || (cfg->in_csi & PRP_CSI_LOOP) != PRP_CSI_LOOP) return -1; if (cfg->ch1_ptr2) __raw_writel(cfg->ch1_ptr2, PRP_DEST_RGB2_PTR); else return -1; return 0;}/*! * @brief Set PrP channel 2 output buffer 1 address. * @param cfg Pointer to PrP configuration parameter * @return Zero on success, others on failure */int prphw_ch2ptr(emma_prp_cfg * cfg){ u32 size; if (cfg->ch2_pix == PRP_PIX2_UNUSED) return -1; __raw_writel(cfg->ch2_ptr, PRP_DEST_Y_PTR); if (cfg->ch2_pix == PRP_PIX2_YUV420) { size = cfg->ch2_width * cfg->ch2_height; __raw_writel(cfg->ch2_ptr + size, PRP_DEST_CB_PTR); __raw_writel(cfg->ch2_ptr + size + (size >> 2), PRP_DEST_CR_PTR); } __raw_writel(__raw_readl(PRP_CNTL) | PRP_CNTL_CH2B1, PRP_CNTL); return 0;}/*! * @brief Set PrP channel 2 output buffer 2 address. * @param cfg Pointer to PrP configuration parameter * @return Zero on success, others on failure */int prphw_ch2ptr2(emma_prp_cfg * cfg){ u32 size; if (cfg->ch2_pix == PRP_PIX2_UNUSED || (cfg->in_csi & PRP_CSI_LOOP) != PRP_CSI_LOOP) return -1; __raw_writel(cfg->ch2_ptr2, PRP_SOURCE_Y_PTR); if (cfg->ch2_pix == PRP_PIX2_YUV420) { size = cfg->ch2_width * cfg->ch2_height; __raw_writel(cfg->ch2_ptr2 + size, PRP_SOURCE_CB_PTR); __raw_writel(cfg->ch2_ptr2 + size + (size >> 2), PRP_SOURCE_CR_PTR); } __raw_writel(__raw_readl(PRP_CNTL) | PRP_CNTL_CH2B2, PRP_CNTL); return 0;}/*! * @brief Build CSC table * @param csc CSC table * in csc[0]=index 0..3 : A.1 A.0 B.1 B.0 * csc[1]=direction 0 : YUV2RGB 1 : RGB2YUV * out csc[0..4] are coefficients c[9] is offset * csc[0..8] are coefficients c[9] is offset */void csc_tbl(short csc[10]){ static const unsigned short _r2y[][9] = { {0x4D, 0x4B, 0x3A, 0x57, 0x55, 0x40, 0x40, 0x6B, 0x29}, {0x42, 0x41, 0x32, 0x4C, 0x4A, 0x38, 0x38, 0x5E, 0x24}, {0x36, 0x5C, 0x25, 0x3B, 0x63, 0x40, 0x40, 0x74, 0x18}, {0x2F, 0x4F, 0x20, 0x34, 0x57, 0x38, 0x38, 0x66, 0x15}, }; static const unsigned short _y2r[][5] = { {0x80, 0xb4, 0x2c, 0x5b, 0x0e4}, {0x95, 0xcc, 0x32, 0x68, 0x104}, {0x80, 0xca, 0x18, 0x3c, 0x0ec}, {0x95, 0xe5, 0x1b, 0x44, 0x1e0}, }; unsigned short *_csc; int _csclen; csc[9] = csc[0] & 1; _csclen = csc[0] & 3; if (csc[1]) { _csc = (unsigned short *)_r2y[_csclen]; _csclen = sizeof(_r2y[0]); } else { _csc = (unsigned short *)_y2r[_csclen]; _csclen = sizeof(_y2r[0]); memset(csc + 5, 0, sizeof(short) * 4); } memcpy(csc, _csc, _csclen);}/*! * @brief Setup PrP resize coefficient registers * * @param ch PrP channel number * @param dir Direction, 0 - horizontal, 1 - vertical * @param scale The pointer to scale_t structure */static void prp_set_scaler(int ch, int dir, scale_t * scale){ int i; unsigned int coeff[2]; unsigned int valid; for (coeff[0] = coeff[1] = valid = 0, i = 19; i >= 0; i--) { int j; j = i > 9 ? 1 : 0; coeff[j] = (coeff[j] << BC_COEF) | (scale->tbl[i] & (SZ_COEF - 1)); if (i == 5 || i == 15) coeff[j] <<= 1; valid = (valid << 1) | (scale->tbl[i] >> BC_COEF); } valid |= (scale->len << 24) | ((2 - scale->algo) << 31); for (i = 0; i < 2; i++) (*PRP_RSZ_COEFF)[1 - ch][dir].coeff[i] = coeff[i]; (*PRP_RSZ_COEFF)[1 - ch][dir].cntl = valid;}/*! * @brief Setup PrP registers relevant to input. * @param cfg Pointer to PrP configuration parameter * @param prp_cntl Holds the value for PrP control register * @return Zero on success, others on failure */static int prphw_input_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl){ unsigned long mask; switch (cfg->in_pix) { case PRP_PIXIN_YUV420: *prp_cntl |= PRP_CNTL_IN_YUV420; mask = 0x7; break; case PRP_PIXIN_YUYV: case PRP_PIXIN_YVYU: case PRP_PIXIN_UYVY: case PRP_PIXIN_VYUY: *prp_cntl |= PRP_CNTL_IN_YUV422; mask = 0x1; break; case PRP_PIXIN_RGB565: *prp_cntl |= PRP_CNTL_IN_RGB16; mask = 0x1; break; case PRP_PIXIN_RGB888: *prp_cntl |= PRP_CNTL_IN_RGB32; mask = 0; break; default: pr_debug("Unsupported input pix format 0x%08X\n", cfg->in_pix); return -1; } /* align the input image width */ if (cfg->in_width & mask) { pr_debug("in_width misaligned. in_width=%d\n", cfg->in_width); return -1; } if ((cfg->in_width < PRP_MIN_IN_WIDTH) || (cfg->in_width > PRP_MAX_IN_WIDTH)) { pr_debug("Unsupported input width %d\n", cfg->in_width); return -1; } cfg->in_height &= ~1; /* truncate to make even */ if ((cfg->in_height < PRP_MIN_IN_HEIGHT) || (cfg->in_height > PRP_MAX_IN_HEIGHT)) { pr_debug("Unsupported input height %d\n", cfg->in_height); return -1; } if (!(cfg->in_csi & PRP_CSI_EN)) if (!cfg->in_line_stride) cfg->in_line_stride = cfg->in_width; __raw_writel(cfg->in_pix, PRP_SRC_PIXEL_FORMAT_CNTL); __raw_writel((cfg->in_width << 16) | cfg->in_height, PRP_SOURCE_FRAME_SIZE); __raw_writel((cfg->in_line_skip << 16) | cfg->in_line_stride, PRP_SOURCE_LINE_STRIDE); if (!(cfg->in_csi & PRP_CSI_EN)) { __raw_writel(cfg->in_ptr, PRP_SOURCE_Y_PTR); if (cfg->in_pix == PRP_PIXIN_YUV420) { unsigned int size; size = cfg->in_line_stride * cfg->in_height; __raw_writel(cfg->in_ptr + size, PRP_SOURCE_CB_PTR); __raw_writel(cfg->in_ptr + size + (size >> 2), PRP_SOURCE_CR_PTR); } } /* always cropping */ *prp_cntl |= PRP_CNTL_WINEN; /* color space conversion */ if (!cfg->in_csc[1]) { if (cfg->in_csc[0] > 3) { pr_debug("in_csc invalid 0x%X\n", cfg->in_csc[0]); return -1; } if ((cfg->in_pix == PRP_PIXIN_RGB565) || (cfg->in_pix == PRP_PIXIN_RGB888)) cfg->in_csc[1] = 1; else cfg->in_csc[0] = 0; csc_tbl(cfg->in_csc); } __raw_writel((cfg->in_csc[0] << 21) | (cfg->in_csc[1] << 11) | cfg->in_csc[2], PRP_CSC_COEF_012); __raw_writel((cfg->in_csc[3] << 21) | (cfg->in_csc[4] << 11) | cfg->in_csc[5], PRP_CSC_COEF_345); __raw_writel((cfg->in_csc[6] << 21) | (cfg->in_csc[7] << 11) | cfg->in_csc[8] | (cfg->in_csc[9] << 31), PRP_CSC_COEF_678); if (cfg->in_csi & PRP_CSI_EN) { *prp_cntl |= PRP_CNTL_CSI; /* loop mode enable, ch1 ch2 together */ if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) *prp_cntl |= (PRP_CNTL_CH1_LOOP | PRP_CNTL_CH2_LOOP); } return 0;}/*! * @brief Setup PrP registers relevant to channel 2. * @param cfg Pointer to PrP configuration parameter * @param prp_cntl Holds the value for PrP control register * @return Zero on success, others on failure */static int prphw_ch2_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl){ switch (cfg->ch2_pix) { case PRP_PIX2_YUV420: *prp_cntl |= PRP_CNTL_CH2_YUV420; break; case PRP_PIX2_YUV422: *prp_cntl |= PRP_CNTL_CH2_YUV422; break; case PRP_PIX2_YUV444: *prp_cntl |= PRP_CNTL_CH2_YUV444; break; case PRP_PIX2_UNUSED: return 0; default: pr_debug("Unsupported channel 2 pix format 0x%08X\n", cfg->ch2_pix); return -1; } if (cfg->ch2_pix == PRP_PIX2_YUV420) { cfg->ch2_height &= ~1; /* ensure U/V presence */ cfg->ch2_width &= ~7; /* ensure U/V word aligned */ } else if (cfg->ch2_pix == PRP_PIX2_YUV422) { cfg->ch2_width &= ~1; /* word aligned */ } __raw_writel((cfg->ch2_width << 16) | cfg->ch2_height, PRP_CH2_OUT_IMAGE_SIZE); if (cfg->ch2_pix == PRP_PIX2_YUV420) { u32 size; /* Luminanance band start address */ __raw_writel(cfg->ch2_ptr, PRP_DEST_Y_PTR); if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) { if (!cfg->ch2_ptr2) __raw_writel(cfg->ch2_ptr, PRP_SOURCE_Y_PTR); else __raw_writel(cfg->ch2_ptr2, PRP_SOURCE_Y_PTR); } /* Cb and Cr band start address */ size = cfg->ch2_width * cfg->ch2_height; __raw_writel(cfg->ch2_ptr + size, PRP_DEST_CB_PTR); __raw_writel(cfg->ch2_ptr + size + (size >> 2), PRP_DEST_CR_PTR); if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) { if (!cfg->ch2_ptr2) { __raw_writel(cfg->ch2_ptr + size, PRP_SOURCE_CB_PTR); __raw_writel(cfg->ch2_ptr + size + (size >> 2), PRP_SOURCE_CR_PTR); } else { __raw_writel(cfg->ch2_ptr2 + size, PRP_SOURCE_CB_PTR); __raw_writel(cfg->ch2_ptr2 + size + (size >> 2), PRP_SOURCE_CR_PTR); } } } else { /* Pixel interleaved YUV422 or YUV444 */ __raw_writel(cfg->ch2_ptr, PRP_DEST_Y_PTR); if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) { if (!cfg->ch2_ptr2) __raw_writel(cfg->ch2_ptr, PRP_SOURCE_Y_PTR); else __raw_writel(cfg->ch2_ptr2, PRP_SOURCE_Y_PTR); } } *prp_cntl |= PRP_CNTL_CH2B1 | PRP_CNTL_CH2B2; return 0;}/*! * @brief Setup PrP registers relevant to channel 1. * @param cfg Pointer to PrP configuration parameter * @param prp_cntl Holds the value for PrP control register * @return Zero on success, others on failure */static int prphw_ch1_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl){ int ch1_bpp = 0; switch (cfg->ch1_pix) { case PRP_PIX1_RGB332: *prp_cntl |= PRP_CNTL_CH1_RGB8; ch1_bpp = 1; break; case PRP_PIX1_RGB565: *prp_cntl |= PRP_CNTL_CH1_RGB16; ch1_bpp = 2; break; case PRP_PIX1_RGB888: *prp_cntl |= PRP_CNTL_CH1_RGB32; ch1_bpp = 4; break; case PRP_PIX1_YUYV: case PRP_PIX1_YVYU: case PRP_PIX1_UYVY: case PRP_PIX1_VYUY: *prp_cntl |= PRP_CNTL_CH1_YUV422; ch1_bpp = 2; break; case PRP_PIX1_UNUSED: return 0; default: pr_debug("Unsupported channel 1 pix format 0x%08X\n", cfg->ch1_pix); return -1; } /* parallel or cascade resize */ if (cfg->ch1_scale.algo & PRP_ALGO_BYPASS) *prp_cntl |= PRP_CNTL_UNCHAIN; /* word align */ if (ch1_bpp == 2) cfg->ch1_width &= ~1; else if (ch1_bpp == 1) cfg->ch1_width &= ~3; if (!cfg->ch1_stride) cfg->ch1_stride = cfg->ch1_width; __raw_writel(cfg->ch1_pix, PRP_CH1_PIXEL_FORMAT_CNTL); __raw_writel((cfg->ch1_width << 16) | cfg->ch1_height, PRP_CH1_OUT_IMAGE_SIZE); __raw_writel(cfg->ch1_stride * ch1_bpp, PRP_CH1_LINE_STRIDE); __raw_writel(cfg->ch1_ptr, PRP_DEST_RGB1_PTR); /* double buffer for loop mode */ if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) { if (cfg->ch1_ptr2) __raw_writel(cfg->ch1_ptr2, PRP_DEST_RGB2_PTR); else __raw_writel(cfg->ch1_ptr, PRP_DEST_RGB2_PTR); } return 0;}/*! * @brief Setup PrP registers. * @param cfg Pointer to PrP configuration parameter * @return Zero on success, others on failure */int prphw_cfg(emma_prp_cfg * cfg){ unsigned long prp_cntl = 0; unsigned long val; /* input pixel format checking */ if (prphw_input_cfg(cfg, &prp_cntl)) return -1; if (prphw_ch2_cfg(cfg, &prp_cntl)) return -1; if (prphw_ch1_cfg(cfg, &prp_cntl)) return -1; /* register setting */ __raw_writel(prp_cntl, PRP_CNTL); /* interrupt configuration */ val = PRP_INTRCNTL_RDERR | PRP_INTRCNTL_LBOVF; if (cfg->ch1_pix != PRP_PIX1_UNUSED) val |= PRP_INTRCNTL_CH1FC | PRP_INTRCNTL_CH1WERR; if (cfg->ch2_pix != PRP_PIX2_UNUSED) val |= PRP_INTRCNTL_CH2FC | PRP_INTRCNTL_CH2WERR | PRP_INTRCNTL_CH2OVF; __raw_writel(val, PRP_INTRCNTL); prp_set_scaler(1, 0, &cfg->scale[0]); /* Channel 1 width */ prp_set_scaler(1, 1, &cfg->scale[1]); /* Channel 1 height */ prp_set_scaler(0, 0, &cfg->scale[2]); /* Channel 2 width */ prp_set_scaler(0, 1, &cfg->scale[3]); /* Channel 2 height */ prp_dump(); return 0;}/*! * @brief Check PrP interrupt status. * @return PrP interrupt status */int prphw_isr(void){ int status; status = __raw_readl(PRP_INTRSTATUS) & 0x1FF; if (status & (PRP_INTRSTAT_RDERR | PRP_INTRSTAT_CH1WERR | PRP_INTRSTAT_CH2WERR)) pr_debug("isr bus error. status= 0x%08X\n", status); else if (status & PRP_INTRSTAT_CH2OVF) pr_debug("isr ch 2 buffer overflow. status= 0x%08X\n", status); else if (status & PRP_INTRSTAT_LBOVF) pr_debug("isr line buffer overflow. status= 0x%08X\n", status); /* silicon bug?? enable bit does not self clear? */ if (!(__raw_readl(PRP_CNTL) & PRP_CNTL_CH1_LOOP)) __raw_writel(__raw_readl(PRP_CNTL) & (~PRP_CNTL_CH1EN), PRP_CNTL); if (!(__raw_readl(PRP_CNTL) & PRP_CNTL_CH2_LOOP)) __raw_writel(__raw_readl(PRP_CNTL) & (~PRP_CNTL_CH2EN), PRP_CNTL); __raw_writel(status, PRP_INTRSTATUS); /* clr irq */ return status;}static struct clk *emma_clk;/*! * @brief PrP module clock enable */void prphw_init(void){ emma_clk = clk_get(NULL, "emma_clk"); clk_enable(emma_clk);}/*! * @brief PrP module clock disable */void prphw_exit(void){ clk_disable(emma_clk); clk_put(emma_clk);}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -